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 1858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1869 } | 1869 } |
1870 | 1870 |
1871 | 1871 |
1872 void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) { | 1872 void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) { |
1873 Isolate* isolate = parent->GetIsolate(); | 1873 Isolate* isolate = parent->GetIsolate(); |
1874 Handle<Name> name = isolate->factory()->elements_transition_symbol(); | 1874 Handle<Name> name = isolate->factory()->elements_transition_symbol(); |
1875 ConnectTransition(parent, child, name, SPECIAL_TRANSITION); | 1875 ConnectTransition(parent, child, name, SPECIAL_TRANSITION); |
1876 } | 1876 } |
1877 | 1877 |
1878 | 1878 |
1879 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) { | 1879 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, |
1880 int expected_additional_properties) { | |
1880 if (object->map() == *new_map) return; | 1881 if (object->map() == *new_map) return; |
1882 Handle<Map> old_map(object->map()); | |
1881 if (object->HasFastProperties()) { | 1883 if (object->HasFastProperties()) { |
1882 if (!new_map->is_dictionary_map()) { | 1884 if (!new_map->is_dictionary_map()) { |
1883 Handle<Map> old_map(object->map()); | |
1884 MigrateFastToFast(object, new_map); | 1885 MigrateFastToFast(object, new_map); |
1885 if (old_map->is_prototype_map()) { | 1886 if (old_map->is_prototype_map()) { |
1886 // Clear out the old descriptor array to avoid problems to sharing | 1887 // Clear out the old descriptor array to avoid problems to sharing |
1887 // the descriptor array without using an explicit. | 1888 // the descriptor array without using an explicit. |
1888 old_map->InitializeDescriptors( | 1889 old_map->InitializeDescriptors( |
1889 old_map->GetHeap()->empty_descriptor_array(), | 1890 old_map->GetHeap()->empty_descriptor_array(), |
1890 LayoutDescriptor::FastPointerLayout()); | 1891 LayoutDescriptor::FastPointerLayout()); |
1891 // Ensure that no transition was inserted for prototype migrations. | 1892 // Ensure that no transition was inserted for prototype migrations. |
1892 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( | 1893 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( |
1893 old_map->raw_transitions())); | 1894 old_map->raw_transitions())); |
1894 DCHECK(new_map->GetBackPointer()->IsUndefined()); | 1895 DCHECK(new_map->GetBackPointer()->IsUndefined()); |
1895 } | 1896 } |
1896 } else { | 1897 } else { |
1897 MigrateFastToSlow(object, new_map, 0); | 1898 MigrateFastToSlow(object, new_map, expected_additional_properties); |
1898 } | 1899 } |
1899 } else { | 1900 } else { |
1900 // For slow-to-fast migrations JSObject::TransformToFastProperties() | 1901 // For slow-to-fast migrations JSObject::MigrateSlowToFast() |
1901 // must be used instead. | 1902 // must be used instead. |
1902 CHECK(new_map->is_dictionary_map()); | 1903 CHECK(new_map->is_dictionary_map()); |
1903 | 1904 |
1904 // Slow-to-slow migration is trivial. | 1905 // Slow-to-slow migration is trivial. |
1905 object->set_map(*new_map); | 1906 object->set_map(*new_map); |
1906 } | 1907 } |
1908 if (old_map->is_prototype_map()) { | |
1909 new_map->set_prototype_info(old_map->prototype_info()); | |
1910 old_map->set_prototype_info(Smi::FromInt(0)); | |
1911 } | |
1907 } | 1912 } |
1908 | 1913 |
1909 | 1914 |
1910 // To migrate a fast instance to a fast map: | 1915 // To migrate a fast instance to a fast map: |
1911 // - First check whether the instance needs to be rewritten. If not, simply | 1916 // - First check whether the instance needs to be rewritten. If not, simply |
1912 // change the map. | 1917 // change the map. |
1913 // - Otherwise, allocate a fixed array large enough to hold all fields, in | 1918 // - Otherwise, allocate a fixed array large enough to hold all fields, in |
1914 // addition to unused space. | 1919 // addition to unused space. |
1915 // - Copy all existing properties in, in the following order: backing store | 1920 // - Copy all existing properties in, in the following order: backing store |
1916 // properties, unused fields, inobject properties. | 1921 // properties, unused fields, inobject properties. |
(...skipping 2567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4484 | 4489 |
4485 void JSObject::NormalizeProperties(Handle<JSObject> object, | 4490 void JSObject::NormalizeProperties(Handle<JSObject> object, |
4486 PropertyNormalizationMode mode, | 4491 PropertyNormalizationMode mode, |
4487 int expected_additional_properties, | 4492 int expected_additional_properties, |
4488 const char* reason) { | 4493 const char* reason) { |
4489 if (!object->HasFastProperties()) return; | 4494 if (!object->HasFastProperties()) return; |
4490 | 4495 |
4491 Handle<Map> map(object->map()); | 4496 Handle<Map> map(object->map()); |
4492 Handle<Map> new_map = Map::Normalize(map, mode, reason); | 4497 Handle<Map> new_map = Map::Normalize(map, mode, reason); |
4493 | 4498 |
4494 MigrateFastToSlow(object, new_map, expected_additional_properties); | 4499 MigrateToMap(object, new_map, expected_additional_properties); |
Jakob Kummerow
2015/03/24 10:40:13
MigrateToMap is now *the* choke point for changing
| |
4495 } | 4500 } |
4496 | 4501 |
4497 | 4502 |
4498 void JSObject::MigrateFastToSlow(Handle<JSObject> object, | 4503 void JSObject::MigrateFastToSlow(Handle<JSObject> object, |
4499 Handle<Map> new_map, | 4504 Handle<Map> new_map, |
4500 int expected_additional_properties) { | 4505 int expected_additional_properties) { |
4501 // The global object is always normalized. | 4506 // The global object is always normalized. |
4502 DCHECK(!object->IsGlobalObject()); | 4507 DCHECK(!object->IsGlobalObject()); |
4503 // JSGlobalProxy must never be normalized | 4508 // JSGlobalProxy must never be normalized |
4504 DCHECK(!object->IsJSGlobalProxy()); | 4509 DCHECK(!object->IsJSGlobalProxy()); |
(...skipping 5354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9859 if (details.representation().IsHeapObject() || | 9864 if (details.representation().IsHeapObject() || |
9860 details.representation().IsTagged()) { | 9865 details.representation().IsTagged()) { |
9861 FieldIndex index = FieldIndex::ForDescriptor(map, i); | 9866 FieldIndex index = FieldIndex::ForDescriptor(map, i); |
9862 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true; | 9867 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true; |
9863 } | 9868 } |
9864 } | 9869 } |
9865 return false; | 9870 return false; |
9866 } | 9871 } |
9867 | 9872 |
9868 | 9873 |
9874 // static | |
9869 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, | 9875 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
9870 PrototypeOptimizationMode mode) { | 9876 PrototypeOptimizationMode mode) { |
9871 if (object->IsGlobalObject()) return; | 9877 if (object->IsGlobalObject()) return; |
9872 if (object->IsJSGlobalProxy()) return; | 9878 if (object->IsJSGlobalProxy()) return; |
9873 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { | 9879 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { |
9874 // First normalize to ensure all JSFunctions are DATA_CONSTANT. | 9880 // First normalize to ensure all JSFunctions are DATA_CONSTANT. |
9875 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, | 9881 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, |
9876 "NormalizeAsPrototype"); | 9882 "NormalizeAsPrototype"); |
9877 } | 9883 } |
9878 bool has_just_copied_map = false; | 9884 Handle<Map> previous_map(object->map()); |
9879 if (!object->HasFastProperties()) { | 9885 if (!object->HasFastProperties()) { |
9880 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); | 9886 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); |
9881 has_just_copied_map = true; | |
9882 } | 9887 } |
9883 if (mode == FAST_PROTOTYPE && object->HasFastProperties() && | 9888 if (!object->map()->is_prototype_map()) { |
9884 !object->map()->is_prototype_map()) { | 9889 if (object->map() == *previous_map) { |
9885 if (!has_just_copied_map) { | |
9886 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); | 9890 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); |
9887 JSObject::MigrateToMap(object, new_map); | 9891 JSObject::MigrateToMap(object, new_map); |
9888 } | 9892 } |
9889 Object* maybe_constructor = object->map()->GetConstructor(); | 9893 Object* maybe_constructor = object->map()->GetConstructor(); |
9890 if (maybe_constructor->IsJSFunction()) { | 9894 if (maybe_constructor->IsJSFunction()) { |
9891 JSFunction* constructor = JSFunction::cast(maybe_constructor); | 9895 JSFunction* constructor = JSFunction::cast(maybe_constructor); |
9892 // Replace the pointer to the exact constructor with the Object function | 9896 // Replace the pointer to the exact constructor with the Object function |
9893 // from the same context if undetectable from JS. This is to avoid keeping | 9897 // from the same context if undetectable from JS. This is to avoid keeping |
9894 // memory alive unnecessarily. | 9898 // memory alive unnecessarily. |
9895 if (!constructor->shared()->IsApiFunction() && | 9899 if (!constructor->shared()->IsApiFunction() && |
9896 object->class_name() == | 9900 object->class_name() == |
9897 object->GetIsolate()->heap()->Object_string()) { | 9901 object->GetIsolate()->heap()->Object_string()) { |
9898 Context* context = constructor->context()->native_context(); | 9902 Context* context = constructor->context()->native_context(); |
9899 JSFunction* object_function = context->object_function(); | 9903 JSFunction* object_function = context->object_function(); |
9900 object->map()->SetConstructor(object_function); | 9904 object->map()->SetConstructor(object_function); |
9901 } | 9905 } |
9902 } | 9906 } |
9903 object->map()->set_is_prototype_map(true); | 9907 object->map()->set_is_prototype_map(true); |
9904 } | 9908 } |
9905 } | 9909 } |
9906 | 9910 |
9907 | 9911 |
9912 // static | |
9908 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { | 9913 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { |
9909 if (!object->map()->is_prototype_map()) return; | 9914 if (!object->map()->is_prototype_map()) return; |
9910 OptimizeAsPrototype(object, FAST_PROTOTYPE); | 9915 OptimizeAsPrototype(object, FAST_PROTOTYPE); |
9911 } | 9916 } |
9912 | 9917 |
9913 | 9918 |
9919 // static | |
9914 void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype, | 9920 void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype, |
9915 Handle<HeapObject> user) { | 9921 Handle<HeapObject> user) { |
9916 DCHECK(FLAG_track_prototype_users); | 9922 DCHECK(FLAG_track_prototype_users); |
9917 Isolate* isolate = prototype->GetIsolate(); | 9923 Isolate* isolate = prototype->GetIsolate(); |
9918 Handle<Name> symbol = isolate->factory()->prototype_users_symbol(); | 9924 if (prototype->IsJSGlobalProxy()) { |
9919 | 9925 prototype = handle(JSObject::cast(prototype->map()->prototype()), isolate); |
9920 // Get prototype users array, create it if it doesn't exist yet. | 9926 } |
9921 Handle<Object> maybe_array = | 9927 Handle<PrototypeInfo> proto_info; |
9922 JSObject::GetProperty(prototype, symbol).ToHandleChecked(); | 9928 Object* maybe_proto_info = prototype->map()->prototype_info(); |
9923 | 9929 if (maybe_proto_info->IsPrototypeInfo()) { |
9924 Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_array, user); | 9930 proto_info = handle(PrototypeInfo::cast(maybe_proto_info), isolate); |
9925 if (!maybe_array.is_identical_to(new_array)) { | 9931 } else { |
9926 JSObject::SetOwnPropertyIgnoreAttributes(prototype, symbol, new_array, | 9932 proto_info = isolate->factory()->NewPrototypeInfo(prototype); |
9927 DONT_ENUM).Assert(); | 9933 prototype->map()->set_prototype_info(*proto_info); |
9934 } | |
9935 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); | |
9936 Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_registry, user); | |
9937 if (!maybe_registry.is_identical_to(new_array)) { | |
9938 proto_info->set_prototype_users(*new_array); | |
9928 } | 9939 } |
9929 } | 9940 } |
9930 | 9941 |
9931 | 9942 |
9943 // static | |
9932 void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, | 9944 void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, |
9933 Handle<HeapObject> user) { | 9945 Handle<HeapObject> user) { |
9934 Isolate* isolate = prototype->GetIsolate(); | 9946 Isolate* isolate = prototype->GetIsolate(); |
9935 Handle<Name> symbol = isolate->factory()->prototype_users_symbol(); | 9947 if (prototype->IsJSGlobalProxy()) { |
9936 | 9948 prototype = handle(JSObject::cast(prototype->map()->prototype()), isolate); |
9937 Handle<Object> maybe_array = | 9949 } |
9938 JSObject::GetProperty(prototype, symbol).ToHandleChecked(); | 9950 DCHECK(prototype->map()->is_prototype_map()); |
9939 if (!maybe_array->IsWeakFixedArray()) return; | 9951 Object* maybe_proto_info = prototype->map()->prototype_info(); |
9940 Handle<WeakFixedArray>::cast(maybe_array)->Remove(user); | 9952 if (!maybe_proto_info->IsPrototypeInfo()) return; |
9953 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), | |
9954 isolate); | |
9955 Object* maybe_registry = proto_info->prototype_users(); | |
9956 if (!maybe_registry->IsWeakFixedArray()) return; | |
9957 WeakFixedArray::cast(maybe_registry)->Remove(user); | |
9941 } | 9958 } |
9942 | 9959 |
9943 | 9960 |
9944 void Map::SetPrototype(Handle<Object> prototype, | 9961 void Map::SetPrototype(Handle<Object> prototype, |
9945 PrototypeOptimizationMode proto_mode) { | 9962 PrototypeOptimizationMode proto_mode) { |
9946 if (this->prototype()->IsJSObject() && FLAG_track_prototype_users) { | 9963 if (this->prototype()->IsJSObject() && FLAG_track_prototype_users) { |
9947 Handle<JSObject> old_prototype(JSObject::cast(this->prototype())); | 9964 Handle<JSObject> old_prototype(JSObject::cast(this->prototype())); |
9948 JSObject::UnregisterPrototypeUser(old_prototype, handle(this)); | 9965 JSObject::UnregisterPrototypeUser(old_prototype, handle(this)); |
9949 } | 9966 } |
9950 if (prototype->IsJSObject()) { | 9967 if (prototype->IsJSObject()) { |
9951 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); | 9968 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); |
9952 if (ShouldRegisterAsPrototypeUser(prototype_jsobj)) { | 9969 if (ShouldRegisterAsPrototypeUser(prototype_jsobj)) { |
9953 JSObject::RegisterPrototypeUser(prototype_jsobj, handle(this)); | 9970 JSObject::RegisterPrototypeUser(prototype_jsobj, handle(this)); |
9954 } | 9971 } |
9955 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); | 9972 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); |
9956 } | 9973 } |
9957 WriteBarrierMode wb_mode = | 9974 WriteBarrierMode wb_mode = |
9958 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; | 9975 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; |
9959 set_prototype(*prototype, wb_mode); | 9976 set_prototype(*prototype, wb_mode); |
9960 } | 9977 } |
9961 | 9978 |
9962 | 9979 |
9963 bool Map::ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype) { | 9980 bool Map::ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype) { |
9964 if (!FLAG_track_prototype_users) return false; | 9981 if (!FLAG_track_prototype_users) return false; |
9965 if (this->is_prototype_map()) return true; | 9982 if (this->is_prototype_map()) return true; |
9966 if (this->is_dictionary_map()) return false; | |
9967 Object* back = GetBackPointer(); | 9983 Object* back = GetBackPointer(); |
9968 if (!back->IsMap()) return true; | 9984 if (!back->IsMap()) return true; |
9969 if (Map::cast(back)->prototype() != *prototype) return true; | 9985 if (Map::cast(back)->prototype() != *prototype) return true; |
9970 return false; | 9986 return false; |
9971 } | 9987 } |
9972 | 9988 |
9973 | 9989 |
9974 bool Map::CanUseOptimizationsBasedOnPrototypeRegistry() { | |
9975 if (!FLAG_track_prototype_users) return false; | |
9976 if (this->is_prototype_map()) return true; | |
9977 if (GetBackPointer()->IsMap()) return true; | |
9978 return false; | |
9979 } | |
9980 | |
9981 | |
9982 Handle<Object> CacheInitialJSArrayMaps( | 9990 Handle<Object> CacheInitialJSArrayMaps( |
9983 Handle<Context> native_context, Handle<Map> initial_map) { | 9991 Handle<Context> native_context, Handle<Map> initial_map) { |
9984 // Replace all of the cached initial array maps in the native context with | 9992 // Replace all of the cached initial array maps in the native context with |
9985 // the appropriate transitioned elements kind maps. | 9993 // the appropriate transitioned elements kind maps. |
9986 Factory* factory = native_context->GetIsolate()->factory(); | 9994 Factory* factory = native_context->GetIsolate()->factory(); |
9987 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( | 9995 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( |
9988 kElementsKindCount, TENURED); | 9996 kElementsKindCount, TENURED); |
9989 | 9997 |
9990 Handle<Map> current_map = initial_map; | 9998 Handle<Map> current_map = initial_map; |
9991 ElementsKind kind = current_map->elements_kind(); | 9999 ElementsKind kind = current_map->elements_kind(); |
(...skipping 7087 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
17079 CompilationInfo* info) { | 17087 CompilationInfo* info) { |
17080 Handle<DependentCode> codes = DependentCode::InsertCompilationInfo( | 17088 Handle<DependentCode> codes = DependentCode::InsertCompilationInfo( |
17081 handle(cell->dependent_code(), info->isolate()), | 17089 handle(cell->dependent_code(), info->isolate()), |
17082 DependentCode::kPropertyCellChangedGroup, info->object_wrapper()); | 17090 DependentCode::kPropertyCellChangedGroup, info->object_wrapper()); |
17083 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); | 17091 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); |
17084 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( | 17092 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( |
17085 cell, info->zone()); | 17093 cell, info->zone()); |
17086 } | 17094 } |
17087 | 17095 |
17088 } } // namespace v8::internal | 17096 } } // namespace v8::internal |
OLD | NEW |