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 "src/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 2897 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2908 } | 2908 } |
2909 | 2909 |
2910 | 2910 |
2911 static inline bool EqualImmutableValues(Object* obj1, Object* obj2) { | 2911 static inline bool EqualImmutableValues(Object* obj1, Object* obj2) { |
2912 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds. | 2912 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds. |
2913 // TODO(ishell): compare AccessorPairs. | 2913 // TODO(ishell): compare AccessorPairs. |
2914 return false; | 2914 return false; |
2915 } | 2915 } |
2916 | 2916 |
2917 | 2917 |
2918 // Invalidates a transition target at |key|, and installs |new_descriptors| over | 2918 // Installs |new_descriptors| over the current instance_descriptors to ensure |
2919 // the current instance_descriptors to ensure proper sharing of descriptor | 2919 // proper sharing of descriptor arrays. |
2920 // arrays. | 2920 void Map::ReplaceDescriptors(DescriptorArray* new_descriptors, |
2921 // Returns true if the transition target at given key was deprecated. | 2921 LayoutDescriptor* new_layout_descriptor) { |
2922 bool Map::DeprecateTarget(PropertyKind kind, Name* key, | |
2923 PropertyAttributes attributes, | |
2924 DescriptorArray* new_descriptors, | |
2925 LayoutDescriptor* new_layout_descriptor) { | |
2926 bool transition_target_deprecated = false; | |
2927 Map* maybe_transition = | |
2928 TransitionArray::SearchTransition(this, kind, key, attributes); | |
2929 if (maybe_transition != NULL) { | |
2930 maybe_transition->DeprecateTransitionTree(); | |
2931 transition_target_deprecated = true; | |
2932 } | |
2933 | |
2934 // Don't overwrite the empty descriptor array or initial map's descriptors. | 2922 // Don't overwrite the empty descriptor array or initial map's descriptors. |
2935 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined()) { | 2923 if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined()) { |
2936 return transition_target_deprecated; | 2924 return; |
2937 } | 2925 } |
2938 | 2926 |
2939 DescriptorArray* to_replace = instance_descriptors(); | 2927 DescriptorArray* to_replace = instance_descriptors(); |
2940 GetHeap()->incremental_marking()->RecordWrites(to_replace); | 2928 GetHeap()->incremental_marking()->RecordWrites(to_replace); |
2941 Map* current = this; | 2929 Map* current = this; |
2942 while (current->instance_descriptors() == to_replace) { | 2930 while (current->instance_descriptors() == to_replace) { |
2943 Object* next = current->GetBackPointer(); | 2931 Object* next = current->GetBackPointer(); |
2944 if (next->IsUndefined()) break; // Stop overwriting at initial map. | 2932 if (next->IsUndefined()) break; // Stop overwriting at initial map. |
2945 current->SetEnumLength(kInvalidEnumCacheSentinel); | 2933 current->SetEnumLength(kInvalidEnumCacheSentinel); |
2946 current->UpdateDescriptors(new_descriptors, new_layout_descriptor); | 2934 current->UpdateDescriptors(new_descriptors, new_layout_descriptor); |
2947 current = Map::cast(next); | 2935 current = Map::cast(next); |
2948 } | 2936 } |
2949 set_owns_descriptors(false); | 2937 set_owns_descriptors(false); |
2950 return transition_target_deprecated; | |
2951 } | 2938 } |
2952 | 2939 |
2953 | 2940 |
2954 Map* Map::FindRootMap() { | 2941 Map* Map::FindRootMap() { |
2955 Map* result = this; | 2942 Map* result = this; |
2956 while (true) { | 2943 while (true) { |
2957 Object* back = result->GetBackPointer(); | 2944 Object* back = result->GetBackPointer(); |
2958 if (back->IsUndefined()) { | 2945 if (back->IsUndefined()) { |
2959 // Initial map always owns descriptors and doesn't have unused entries | 2946 // Initial map always owns descriptors and doesn't have unused entries |
2960 // in the descriptor array. | 2947 // in the descriptor array. |
(...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3606 new_descriptors->Sort(); | 3593 new_descriptors->Sort(); |
3607 | 3594 |
3608 DCHECK(store_mode != FORCE_FIELD || | 3595 DCHECK(store_mode != FORCE_FIELD || |
3609 new_descriptors->GetDetails(modify_index).location() == kField); | 3596 new_descriptors->GetDetails(modify_index).location() == kField); |
3610 | 3597 |
3611 Handle<Map> split_map(root_map->FindLastMatchMap( | 3598 Handle<Map> split_map(root_map->FindLastMatchMap( |
3612 root_nof, old_nof, *new_descriptors), isolate); | 3599 root_nof, old_nof, *new_descriptors), isolate); |
3613 int split_nof = split_map->NumberOfOwnDescriptors(); | 3600 int split_nof = split_map->NumberOfOwnDescriptors(); |
3614 DCHECK_NE(old_nof, split_nof); | 3601 DCHECK_NE(old_nof, split_nof); |
3615 | 3602 |
3616 Handle<LayoutDescriptor> new_layout_descriptor = | |
3617 LayoutDescriptor::New(split_map, new_descriptors, old_nof); | |
3618 | |
3619 PropertyKind split_kind; | 3603 PropertyKind split_kind; |
3620 PropertyAttributes split_attributes; | 3604 PropertyAttributes split_attributes; |
3621 if (modify_index == split_nof) { | 3605 if (modify_index == split_nof) { |
3622 split_kind = new_kind; | 3606 split_kind = new_kind; |
3623 split_attributes = new_attributes; | 3607 split_attributes = new_attributes; |
3624 } else { | 3608 } else { |
3625 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof); | 3609 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof); |
3626 split_kind = split_prop_details.kind(); | 3610 split_kind = split_prop_details.kind(); |
3627 split_attributes = split_prop_details.attributes(); | 3611 split_attributes = split_prop_details.attributes(); |
3628 } | 3612 } |
3629 bool transition_target_deprecated = split_map->DeprecateTarget( | |
3630 split_kind, old_descriptors->GetKey(split_nof), split_attributes, | |
3631 *new_descriptors, *new_layout_descriptor); | |
3632 | 3613 |
3633 // If |transition_target_deprecated| is true then the transition array | 3614 // Invalidate a transition target at |key|. |
3634 // already contains entry for given descriptor. This means that the transition | 3615 Map* maybe_transition = TransitionArray::SearchTransition( |
| 3616 *split_map, split_kind, old_descriptors->GetKey(split_nof), |
| 3617 split_attributes); |
| 3618 if (maybe_transition != NULL) { |
| 3619 maybe_transition->DeprecateTransitionTree(); |
| 3620 } |
| 3621 |
| 3622 // If |maybe_transition| is not NULL then the transition array already |
| 3623 // contains entry for given descriptor. This means that the transition |
3635 // could be inserted regardless of whether transitions array is full or not. | 3624 // could be inserted regardless of whether transitions array is full or not. |
3636 if (!transition_target_deprecated && | 3625 if (maybe_transition == NULL && |
3637 !TransitionArray::CanHaveMoreTransitions(split_map)) { | 3626 !TransitionArray::CanHaveMoreTransitions(split_map)) { |
3638 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, | 3627 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, |
3639 new_kind, new_attributes, | 3628 new_kind, new_attributes, |
3640 "GenAll_CantHaveMoreTransitions"); | 3629 "GenAll_CantHaveMoreTransitions"); |
3641 } | 3630 } |
3642 | 3631 |
3643 old_map->NotifyLeafMapLayoutChange(); | 3632 old_map->NotifyLeafMapLayoutChange(); |
3644 | 3633 |
3645 if (FLAG_trace_generalization && modify_index >= 0) { | 3634 if (FLAG_trace_generalization && modify_index >= 0) { |
3646 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); | 3635 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); |
(...skipping 10 matching lines...) Expand all Loading... |
3657 : HeapType::Constant( | 3646 : HeapType::Constant( |
3658 handle(new_descriptors->GetValue(modify_index), isolate), | 3647 handle(new_descriptors->GetValue(modify_index), isolate), |
3659 isolate); | 3648 isolate); |
3660 old_map->PrintGeneralization( | 3649 old_map->PrintGeneralization( |
3661 stdout, "", modify_index, split_nof, old_nof, | 3650 stdout, "", modify_index, split_nof, old_nof, |
3662 old_details.location() == kDescriptor && store_mode == FORCE_FIELD, | 3651 old_details.location() == kDescriptor && store_mode == FORCE_FIELD, |
3663 old_details.representation(), new_details.representation(), | 3652 old_details.representation(), new_details.representation(), |
3664 *old_field_type, *new_field_type); | 3653 *old_field_type, *new_field_type); |
3665 } | 3654 } |
3666 | 3655 |
3667 // Add missing transitions. | 3656 Handle<LayoutDescriptor> new_layout_descriptor = |
3668 Handle<Map> new_map = split_map; | 3657 LayoutDescriptor::New(split_map, new_descriptors, old_nof); |
3669 for (int i = split_nof; i < old_nof; ++i) { | 3658 |
3670 new_map = CopyInstallDescriptors(new_map, i, new_descriptors, | 3659 Handle<Map> new_map = |
3671 new_layout_descriptor); | 3660 AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor); |
3672 } | 3661 |
3673 new_map->set_owns_descriptors(true); | 3662 // Deprecated part of the transition tree is no longer reachable, so replace |
| 3663 // current instance descriptors in the "survived" part of the tree with |
| 3664 // the new descriptors to maintain descriptors sharing invariant. |
| 3665 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor); |
3674 return new_map; | 3666 return new_map; |
3675 } | 3667 } |
3676 | 3668 |
3677 | 3669 |
3678 // Generalize the representation of all DATA descriptors. | 3670 // Generalize the representation of all DATA descriptors. |
3679 Handle<Map> Map::GeneralizeAllFieldRepresentations( | 3671 Handle<Map> Map::GeneralizeAllFieldRepresentations( |
3680 Handle<Map> map) { | 3672 Handle<Map> map) { |
3681 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 3673 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
3682 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) { | 3674 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) { |
3683 PropertyDetails details = descriptors->GetDetails(i); | 3675 PropertyDetails details = descriptors->GetDetails(i); |
(...skipping 5484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9168 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n", | 9160 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n", |
9169 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result), | 9161 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result), |
9170 reason); | 9162 reason); |
9171 } | 9163 } |
9172 #endif | 9164 #endif |
9173 | 9165 |
9174 return result; | 9166 return result; |
9175 } | 9167 } |
9176 | 9168 |
9177 | 9169 |
| 9170 // Creates transition tree starting from |split_map| and adding all descriptors |
| 9171 // starting from descriptor with index |split_map|.NumberOfOwnDescriptors(). |
| 9172 // The way how it is done is tricky because of GC and special descriptors |
| 9173 // marking logic. |
| 9174 Handle<Map> Map::AddMissingTransitions( |
| 9175 Handle<Map> split_map, Handle<DescriptorArray> descriptors, |
| 9176 Handle<LayoutDescriptor> full_layout_descriptor) { |
| 9177 DCHECK(descriptors->IsSortedNoDuplicates()); |
| 9178 int split_nof = split_map->NumberOfOwnDescriptors(); |
| 9179 int nof_descriptors = descriptors->number_of_descriptors(); |
| 9180 DCHECK_LT(split_nof, nof_descriptors); |
| 9181 |
| 9182 // Start with creating last map which will own full descriptors array. |
| 9183 // This is necessary to guarantee that GC will mark the whole descriptor |
| 9184 // array if any of the allocations happening below fail. |
| 9185 // Number of unused properties is temporarily incorrect and the layout |
| 9186 // descriptor could unnecessarily be in slow mode but we will fix after |
| 9187 // all the other intermediate maps are created. |
| 9188 Handle<Map> last_map = CopyDropDescriptors(split_map); |
| 9189 last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor); |
| 9190 last_map->set_unused_property_fields(0); |
| 9191 |
| 9192 // During creation of intermediate maps we violate descriptors sharing |
| 9193 // invariant since the last map is not yet connected to the transition tree |
| 9194 // we create here. But it is safe because GC never trims map's descriptors |
| 9195 // if there are no dead transitions from that map and this is exactly the |
| 9196 // case for all the intermediate maps we create here. |
| 9197 Handle<Map> map = split_map; |
| 9198 for (int i = split_nof; i < nof_descriptors - 1; ++i) { |
| 9199 Handle<Map> new_map = CopyDropDescriptors(map); |
| 9200 InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor); |
| 9201 map = new_map; |
| 9202 } |
| 9203 InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors, |
| 9204 full_layout_descriptor); |
| 9205 return last_map; |
| 9206 } |
| 9207 |
| 9208 |
9178 // Since this method is used to rewrite an existing transition tree, it can | 9209 // Since this method is used to rewrite an existing transition tree, it can |
9179 // always insert transitions without checking. | 9210 // always insert transitions without checking. |
9180 Handle<Map> Map::CopyInstallDescriptors( | 9211 void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child, |
9181 Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors, | 9212 int new_descriptor, |
9182 Handle<LayoutDescriptor> full_layout_descriptor) { | 9213 Handle<DescriptorArray> descriptors, |
| 9214 Handle<LayoutDescriptor> full_layout_descriptor) { |
9183 DCHECK(descriptors->IsSortedNoDuplicates()); | 9215 DCHECK(descriptors->IsSortedNoDuplicates()); |
9184 | 9216 |
9185 Handle<Map> result = CopyDropDescriptors(map); | 9217 child->set_instance_descriptors(*descriptors); |
| 9218 child->SetNumberOfOwnDescriptors(new_descriptor + 1); |
9186 | 9219 |
9187 result->set_instance_descriptors(*descriptors); | 9220 int unused_property_fields = parent->unused_property_fields(); |
9188 result->SetNumberOfOwnDescriptors(new_descriptor + 1); | |
9189 | |
9190 int unused_property_fields = map->unused_property_fields(); | |
9191 PropertyDetails details = descriptors->GetDetails(new_descriptor); | 9221 PropertyDetails details = descriptors->GetDetails(new_descriptor); |
9192 if (details.location() == kField) { | 9222 if (details.location() == kField) { |
9193 unused_property_fields = map->unused_property_fields() - 1; | 9223 unused_property_fields = parent->unused_property_fields() - 1; |
9194 if (unused_property_fields < 0) { | 9224 if (unused_property_fields < 0) { |
9195 unused_property_fields += JSObject::kFieldsAdded; | 9225 unused_property_fields += JSObject::kFieldsAdded; |
9196 } | 9226 } |
9197 } | 9227 } |
9198 result->set_unused_property_fields(unused_property_fields); | 9228 child->set_unused_property_fields(unused_property_fields); |
9199 | 9229 |
9200 if (FLAG_unbox_double_fields) { | 9230 if (FLAG_unbox_double_fields) { |
9201 Handle<LayoutDescriptor> layout_descriptor = | 9231 Handle<LayoutDescriptor> layout_descriptor = |
9202 LayoutDescriptor::AppendIfFastOrUseFull(map, details, | 9232 LayoutDescriptor::AppendIfFastOrUseFull(parent, details, |
9203 full_layout_descriptor); | 9233 full_layout_descriptor); |
9204 result->set_layout_descriptor(*layout_descriptor); | 9234 child->set_layout_descriptor(*layout_descriptor); |
9205 #ifdef VERIFY_HEAP | 9235 #ifdef VERIFY_HEAP |
9206 // TODO(ishell): remove these checks from VERIFY_HEAP mode. | 9236 // TODO(ishell): remove these checks from VERIFY_HEAP mode. |
9207 if (FLAG_verify_heap) { | 9237 if (FLAG_verify_heap) { |
9208 CHECK(result->layout_descriptor()->IsConsistentWithMap(*result)); | 9238 CHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); |
9209 } | 9239 } |
9210 #else | 9240 #else |
9211 SLOW_DCHECK(result->layout_descriptor()->IsConsistentWithMap(*result)); | 9241 SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child)); |
9212 #endif | 9242 #endif |
9213 result->set_visitor_id(Heap::GetStaticVisitorIdForMap(*result)); | 9243 child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child)); |
9214 } | 9244 } |
9215 | 9245 |
9216 Handle<Name> name = handle(descriptors->GetKey(new_descriptor)); | 9246 Handle<Name> name = handle(descriptors->GetKey(new_descriptor)); |
9217 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION); | 9247 ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION); |
9218 | |
9219 return result; | |
9220 } | 9248 } |
9221 | 9249 |
9222 | 9250 |
9223 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind, | 9251 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind, |
9224 TransitionFlag flag) { | 9252 TransitionFlag flag) { |
9225 Map* maybe_elements_transition_map = NULL; | 9253 Map* maybe_elements_transition_map = NULL; |
9226 if (flag == INSERT_TRANSITION) { | 9254 if (flag == INSERT_TRANSITION) { |
9227 maybe_elements_transition_map = map->ElementsTransitionMap(); | 9255 maybe_elements_transition_map = map->ElementsTransitionMap(); |
9228 DCHECK(maybe_elements_transition_map == NULL || | 9256 DCHECK(maybe_elements_transition_map == NULL || |
9229 (maybe_elements_transition_map->elements_kind() == | 9257 (maybe_elements_transition_map->elements_kind() == |
(...skipping 9933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19163 if (cell->value() != *new_value) { | 19191 if (cell->value() != *new_value) { |
19164 cell->set_value(*new_value); | 19192 cell->set_value(*new_value); |
19165 Isolate* isolate = cell->GetIsolate(); | 19193 Isolate* isolate = cell->GetIsolate(); |
19166 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 19194 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
19167 isolate, DependentCode::kPropertyCellChangedGroup); | 19195 isolate, DependentCode::kPropertyCellChangedGroup); |
19168 } | 19196 } |
19169 } | 19197 } |
19170 | 19198 |
19171 } // namespace internal | 19199 } // namespace internal |
19172 } // namespace v8 | 19200 } // namespace v8 |
OLD | NEW |