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 1867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1878 } | 1878 } |
1879 | 1879 |
1880 | 1880 |
1881 void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) { | 1881 void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) { |
1882 Isolate* isolate = parent->GetIsolate(); | 1882 Isolate* isolate = parent->GetIsolate(); |
1883 Handle<Name> name = isolate->factory()->elements_transition_symbol(); | 1883 Handle<Name> name = isolate->factory()->elements_transition_symbol(); |
1884 ConnectTransition(parent, child, name, SPECIAL_TRANSITION); | 1884 ConnectTransition(parent, child, name, SPECIAL_TRANSITION); |
1885 } | 1885 } |
1886 | 1886 |
1887 | 1887 |
1888 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) { | 1888 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, |
1889 int expected_additional_properties) { | |
1889 if (object->map() == *new_map) return; | 1890 if (object->map() == *new_map) return; |
1891 Handle<Map> old_map(object->map()); | |
1890 if (object->HasFastProperties()) { | 1892 if (object->HasFastProperties()) { |
1891 if (!new_map->is_dictionary_map()) { | 1893 if (!new_map->is_dictionary_map()) { |
1892 Handle<Map> old_map(object->map()); | |
1893 MigrateFastToFast(object, new_map); | 1894 MigrateFastToFast(object, new_map); |
1894 if (old_map->is_prototype_map()) { | 1895 if (old_map->is_prototype_map()) { |
1895 // Clear out the old descriptor array to avoid problems to sharing | 1896 // Clear out the old descriptor array to avoid problems to sharing |
1896 // the descriptor array without using an explicit. | 1897 // the descriptor array without using an explicit. |
1897 old_map->InitializeDescriptors( | 1898 old_map->InitializeDescriptors( |
1898 old_map->GetHeap()->empty_descriptor_array(), | 1899 old_map->GetHeap()->empty_descriptor_array(), |
1899 LayoutDescriptor::FastPointerLayout()); | 1900 LayoutDescriptor::FastPointerLayout()); |
1900 // Ensure that no transition was inserted for prototype migrations. | 1901 // Ensure that no transition was inserted for prototype migrations. |
1901 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( | 1902 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( |
1902 old_map->raw_transitions())); | 1903 old_map->raw_transitions())); |
1903 DCHECK(new_map->GetBackPointer()->IsUndefined()); | 1904 DCHECK(new_map->GetBackPointer()->IsUndefined()); |
1904 } | 1905 } |
1905 } else { | 1906 } else { |
1906 MigrateFastToSlow(object, new_map, 0); | 1907 MigrateFastToSlow(object, new_map, expected_additional_properties); |
1907 } | 1908 } |
1908 } else { | 1909 } else { |
1909 // For slow-to-fast migrations JSObject::TransformToFastProperties() | 1910 // For slow-to-fast migrations JSObject::MigrateSlowToFast() |
1910 // must be used instead. | 1911 // must be used instead. |
1911 CHECK(new_map->is_dictionary_map()); | 1912 CHECK(new_map->is_dictionary_map()); |
1912 | 1913 |
1913 // Slow-to-slow migration is trivial. | 1914 // Slow-to-slow migration is trivial. |
1914 object->set_map(*new_map); | 1915 object->set_map(*new_map); |
1915 } | 1916 } |
1917 if (old_map->is_prototype_map()) { | |
1918 new_map->set_prototype_info(old_map->prototype_info()); | |
1919 old_map->set_prototype_info(Smi::FromInt(0)); | |
1920 } | |
1916 } | 1921 } |
1917 | 1922 |
1918 | 1923 |
1919 // To migrate a fast instance to a fast map: | 1924 // To migrate a fast instance to a fast map: |
1920 // - First check whether the instance needs to be rewritten. If not, simply | 1925 // - First check whether the instance needs to be rewritten. If not, simply |
1921 // change the map. | 1926 // change the map. |
1922 // - Otherwise, allocate a fixed array large enough to hold all fields, in | 1927 // - Otherwise, allocate a fixed array large enough to hold all fields, in |
1923 // addition to unused space. | 1928 // addition to unused space. |
1924 // - Copy all existing properties in, in the following order: backing store | 1929 // - Copy all existing properties in, in the following order: backing store |
1925 // properties, unused fields, inobject properties. | 1930 // properties, unused fields, inobject properties. |
(...skipping 2582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4508 | 4513 |
4509 void JSObject::NormalizeProperties(Handle<JSObject> object, | 4514 void JSObject::NormalizeProperties(Handle<JSObject> object, |
4510 PropertyNormalizationMode mode, | 4515 PropertyNormalizationMode mode, |
4511 int expected_additional_properties, | 4516 int expected_additional_properties, |
4512 const char* reason) { | 4517 const char* reason) { |
4513 if (!object->HasFastProperties()) return; | 4518 if (!object->HasFastProperties()) return; |
4514 | 4519 |
4515 Handle<Map> map(object->map()); | 4520 Handle<Map> map(object->map()); |
4516 Handle<Map> new_map = Map::Normalize(map, mode, reason); | 4521 Handle<Map> new_map = Map::Normalize(map, mode, reason); |
4517 | 4522 |
4518 MigrateFastToSlow(object, new_map, expected_additional_properties); | 4523 MigrateToMap(object, new_map, expected_additional_properties); |
4519 } | 4524 } |
4520 | 4525 |
4521 | 4526 |
4522 void JSObject::MigrateFastToSlow(Handle<JSObject> object, | 4527 void JSObject::MigrateFastToSlow(Handle<JSObject> object, |
4523 Handle<Map> new_map, | 4528 Handle<Map> new_map, |
4524 int expected_additional_properties) { | 4529 int expected_additional_properties) { |
4525 // The global object is always normalized. | 4530 // The global object is always normalized. |
4526 DCHECK(!object->IsGlobalObject()); | 4531 DCHECK(!object->IsGlobalObject()); |
4527 // JSGlobalProxy must never be normalized | 4532 // JSGlobalProxy must never be normalized |
4528 DCHECK(!object->IsJSGlobalProxy()); | 4533 DCHECK(!object->IsJSGlobalProxy()); |
(...skipping 5352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9881 if (details.representation().IsHeapObject() || | 9886 if (details.representation().IsHeapObject() || |
9882 details.representation().IsTagged()) { | 9887 details.representation().IsTagged()) { |
9883 FieldIndex index = FieldIndex::ForDescriptor(map, i); | 9888 FieldIndex index = FieldIndex::ForDescriptor(map, i); |
9884 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true; | 9889 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true; |
9885 } | 9890 } |
9886 } | 9891 } |
9887 return false; | 9892 return false; |
9888 } | 9893 } |
9889 | 9894 |
9890 | 9895 |
9896 // static | |
9891 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, | 9897 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
9892 PrototypeOptimizationMode mode) { | 9898 PrototypeOptimizationMode mode) { |
9893 if (object->IsGlobalObject()) return; | 9899 if (object->IsGlobalObject()) return; |
9894 if (object->IsJSGlobalProxy()) return; | 9900 if (object->IsJSGlobalProxy()) return; |
9895 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { | 9901 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { |
9896 // First normalize to ensure all JSFunctions are DATA_CONSTANT. | 9902 // First normalize to ensure all JSFunctions are DATA_CONSTANT. |
9897 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, | 9903 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, |
9898 "NormalizeAsPrototype"); | 9904 "NormalizeAsPrototype"); |
9899 } | 9905 } |
9900 bool has_just_copied_map = false; | 9906 Handle<Map> previous_map(object->map()); |
9901 if (!object->HasFastProperties()) { | 9907 if (!object->HasFastProperties()) { |
9902 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); | 9908 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); |
9903 has_just_copied_map = true; | |
9904 } | 9909 } |
9905 if (mode == FAST_PROTOTYPE && object->HasFastProperties() && | 9910 if (!object->map()->is_prototype_map()) { |
9906 !object->map()->is_prototype_map()) { | 9911 if (object->map() == *previous_map) { |
9907 if (!has_just_copied_map) { | |
9908 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); | 9912 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); |
9909 JSObject::MigrateToMap(object, new_map); | 9913 JSObject::MigrateToMap(object, new_map); |
9910 } | 9914 } |
9911 Object* maybe_constructor = object->map()->GetConstructor(); | 9915 Object* maybe_constructor = object->map()->GetConstructor(); |
9912 if (maybe_constructor->IsJSFunction()) { | 9916 if (maybe_constructor->IsJSFunction()) { |
9913 JSFunction* constructor = JSFunction::cast(maybe_constructor); | 9917 JSFunction* constructor = JSFunction::cast(maybe_constructor); |
9914 // Replace the pointer to the exact constructor with the Object function | 9918 // Replace the pointer to the exact constructor with the Object function |
9915 // from the same context if undetectable from JS. This is to avoid keeping | 9919 // from the same context if undetectable from JS. This is to avoid keeping |
9916 // memory alive unnecessarily. | 9920 // memory alive unnecessarily. |
9917 if (!constructor->shared()->IsApiFunction() && | 9921 if (!constructor->shared()->IsApiFunction() && |
9918 object->class_name() == | 9922 object->class_name() == |
9919 object->GetIsolate()->heap()->Object_string()) { | 9923 object->GetIsolate()->heap()->Object_string()) { |
9920 Context* context = constructor->context()->native_context(); | 9924 Context* context = constructor->context()->native_context(); |
9921 JSFunction* object_function = context->object_function(); | 9925 JSFunction* object_function = context->object_function(); |
9922 object->map()->SetConstructor(object_function); | 9926 object->map()->SetConstructor(object_function); |
9923 } | 9927 } |
9924 } | 9928 } |
9925 object->map()->set_is_prototype_map(true); | 9929 object->map()->set_is_prototype_map(true); |
9926 } | 9930 } |
9927 } | 9931 } |
9928 | 9932 |
9929 | 9933 |
9934 // static | |
9930 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { | 9935 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { |
9931 if (!object->map()->is_prototype_map()) return; | 9936 if (!object->map()->is_prototype_map()) return; |
9932 OptimizeAsPrototype(object, FAST_PROTOTYPE); | 9937 OptimizeAsPrototype(object, FAST_PROTOTYPE); |
9933 } | 9938 } |
9934 | 9939 |
9935 | 9940 |
9941 // static | |
9936 void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype, | 9942 void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype, |
9937 Handle<HeapObject> user) { | 9943 Handle<HeapObject> user) { |
9938 DCHECK(FLAG_track_prototype_users); | 9944 DCHECK(FLAG_track_prototype_users); |
9939 Isolate* isolate = prototype->GetIsolate(); | 9945 Isolate* isolate = prototype->GetIsolate(); |
9940 Handle<Name> symbol = isolate->factory()->prototype_users_symbol(); | 9946 if (prototype->IsJSGlobalProxy()) { |
9941 | 9947 prototype = handle(JSObject::cast(prototype->map()->prototype()), isolate); |
Toon Verwaest
2015/03/26 16:15:33
Use the PrototypeIterator
Jakob Kummerow
2015/03/31 14:20:21
Done.
| |
9942 // Get prototype users array, create it if it doesn't exist yet. | 9948 } |
9943 Handle<Object> maybe_array = | 9949 Handle<PrototypeInfo> proto_info; |
9944 JSObject::GetProperty(prototype, symbol).ToHandleChecked(); | 9950 Object* maybe_proto_info = prototype->map()->prototype_info(); |
9945 | 9951 if (maybe_proto_info->IsPrototypeInfo()) { |
9946 Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_array, user); | 9952 proto_info = handle(PrototypeInfo::cast(maybe_proto_info), isolate); |
9947 if (!maybe_array.is_identical_to(new_array)) { | 9953 } else { |
9948 JSObject::SetOwnPropertyIgnoreAttributes(prototype, symbol, new_array, | 9954 proto_info = isolate->factory()->NewPrototypeInfo(prototype); |
9949 DONT_ENUM).Assert(); | 9955 prototype->map()->set_prototype_info(*proto_info); |
9956 } | |
9957 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); | |
9958 Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_registry, user); | |
9959 if (!maybe_registry.is_identical_to(new_array)) { | |
9960 proto_info->set_prototype_users(*new_array); | |
9950 } | 9961 } |
9951 } | 9962 } |
9952 | 9963 |
9953 | 9964 |
9965 // static | |
9954 void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, | 9966 void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, |
9955 Handle<HeapObject> user) { | 9967 Handle<HeapObject> user) { |
9956 Isolate* isolate = prototype->GetIsolate(); | 9968 Isolate* isolate = prototype->GetIsolate(); |
9957 Handle<Name> symbol = isolate->factory()->prototype_users_symbol(); | 9969 if (prototype->IsJSGlobalProxy()) { |
9958 | 9970 prototype = handle(JSObject::cast(prototype->map()->prototype()), isolate); |
Toon Verwaest
2015/03/26 16:15:33
PrototypeIterator
Jakob Kummerow
2015/03/31 14:20:21
Done.
| |
9959 Handle<Object> maybe_array = | 9971 } |
9960 JSObject::GetProperty(prototype, symbol).ToHandleChecked(); | 9972 DCHECK(prototype->map()->is_prototype_map()); |
9961 if (!maybe_array->IsWeakFixedArray()) return; | 9973 Object* maybe_proto_info = prototype->map()->prototype_info(); |
9962 Handle<WeakFixedArray>::cast(maybe_array)->Remove(user); | 9974 if (!maybe_proto_info->IsPrototypeInfo()) return; |
9975 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), | |
9976 isolate); | |
9977 Object* maybe_registry = proto_info->prototype_users(); | |
9978 if (!maybe_registry->IsWeakFixedArray()) return; | |
9979 WeakFixedArray::cast(maybe_registry)->Remove(user); | |
9963 } | 9980 } |
9964 | 9981 |
9965 | 9982 |
9966 void Map::SetPrototype(Handle<Object> prototype, | 9983 void Map::SetPrototype(Handle<Object> prototype, |
9967 PrototypeOptimizationMode proto_mode) { | 9984 PrototypeOptimizationMode proto_mode) { |
9968 if (this->prototype()->IsJSObject() && FLAG_track_prototype_users) { | 9985 if (this->prototype()->IsJSObject() && FLAG_track_prototype_users) { |
9969 Handle<JSObject> old_prototype(JSObject::cast(this->prototype())); | 9986 Handle<JSObject> old_prototype(JSObject::cast(this->prototype())); |
9970 JSObject::UnregisterPrototypeUser(old_prototype, handle(this)); | 9987 JSObject::UnregisterPrototypeUser(old_prototype, handle(this)); |
9971 } | 9988 } |
9972 if (prototype->IsJSObject()) { | 9989 if (prototype->IsJSObject()) { |
9973 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); | 9990 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); |
9974 if (ShouldRegisterAsPrototypeUser(prototype_jsobj)) { | 9991 if (ShouldRegisterAsPrototypeUser(prototype_jsobj)) { |
9975 JSObject::RegisterPrototypeUser(prototype_jsobj, handle(this)); | 9992 JSObject::RegisterPrototypeUser(prototype_jsobj, handle(this)); |
9976 } | 9993 } |
9977 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); | 9994 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); |
9978 } | 9995 } |
9979 WriteBarrierMode wb_mode = | 9996 WriteBarrierMode wb_mode = |
9980 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; | 9997 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; |
9981 set_prototype(*prototype, wb_mode); | 9998 set_prototype(*prototype, wb_mode); |
9982 } | 9999 } |
9983 | 10000 |
9984 | 10001 |
9985 bool Map::ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype) { | 10002 bool Map::ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype) { |
9986 if (!FLAG_track_prototype_users) return false; | 10003 if (!FLAG_track_prototype_users) return false; |
9987 if (this->is_prototype_map()) return true; | 10004 if (this->is_prototype_map()) return true; |
9988 if (this->is_dictionary_map()) return false; | |
9989 Object* back = GetBackPointer(); | 10005 Object* back = GetBackPointer(); |
9990 if (!back->IsMap()) return true; | 10006 if (!back->IsMap()) return true; |
9991 if (Map::cast(back)->prototype() != *prototype) return true; | 10007 if (Map::cast(back)->prototype() != *prototype) return true; |
9992 return false; | 10008 return false; |
9993 } | 10009 } |
9994 | 10010 |
9995 | 10011 |
9996 bool Map::CanUseOptimizationsBasedOnPrototypeRegistry() { | |
9997 if (!FLAG_track_prototype_users) return false; | |
9998 if (this->is_prototype_map()) return true; | |
9999 if (GetBackPointer()->IsMap()) return true; | |
10000 return false; | |
10001 } | |
10002 | |
10003 | |
10004 Handle<Object> CacheInitialJSArrayMaps( | 10012 Handle<Object> CacheInitialJSArrayMaps( |
10005 Handle<Context> native_context, Handle<Map> initial_map) { | 10013 Handle<Context> native_context, Handle<Map> initial_map) { |
10006 // Replace all of the cached initial array maps in the native context with | 10014 // Replace all of the cached initial array maps in the native context with |
10007 // the appropriate transitioned elements kind maps. | 10015 // the appropriate transitioned elements kind maps. |
10008 Factory* factory = native_context->GetIsolate()->factory(); | 10016 Factory* factory = native_context->GetIsolate()->factory(); |
10009 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( | 10017 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( |
10010 kElementsKindCount, TENURED); | 10018 kElementsKindCount, TENURED); |
10011 | 10019 |
10012 Handle<Map> current_map = initial_map; | 10020 Handle<Map> current_map = initial_map; |
10013 ElementsKind kind = current_map->elements_kind(); | 10021 ElementsKind kind = current_map->elements_kind(); |
(...skipping 7092 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
17106 CompilationInfo* info) { | 17114 CompilationInfo* info) { |
17107 Handle<DependentCode> codes = DependentCode::InsertCompilationInfo( | 17115 Handle<DependentCode> codes = DependentCode::InsertCompilationInfo( |
17108 handle(cell->dependent_code(), info->isolate()), | 17116 handle(cell->dependent_code(), info->isolate()), |
17109 DependentCode::kPropertyCellChangedGroup, info->object_wrapper()); | 17117 DependentCode::kPropertyCellChangedGroup, info->object_wrapper()); |
17110 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); | 17118 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); |
17111 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( | 17119 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( |
17112 cell, info->zone()); | 17120 cell, info->zone()); |
17113 } | 17121 } |
17114 | 17122 |
17115 } } // namespace v8::internal | 17123 } } // namespace v8::internal |
OLD | NEW |