Chromium Code Reviews| 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 |