OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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 3146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3157 InvalidatePrototypeChains(object->map()); | 3157 InvalidatePrototypeChains(object->map()); |
3158 Handle<Map> old_map(object->map()); | 3158 Handle<Map> old_map(object->map()); |
3159 | 3159 |
3160 // If the map was registered with its prototype before, ensure that it | 3160 // If the map was registered with its prototype before, ensure that it |
3161 // registers with its new prototype now. This preserves the invariant that | 3161 // registers with its new prototype now. This preserves the invariant that |
3162 // when a map on a prototype chain is registered with its prototype, then | 3162 // when a map on a prototype chain is registered with its prototype, then |
3163 // all prototypes further up the chain are also registered with their | 3163 // all prototypes further up the chain are also registered with their |
3164 // respective prototypes. | 3164 // respective prototypes. |
3165 UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate()); | 3165 UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate()); |
3166 | 3166 |
3167 if (object->HasFastProperties()) { | 3167 if (old_map->is_dictionary_map()) { |
3168 if (!new_map->is_dictionary_map()) { | |
3169 MigrateFastToFast(object, new_map); | |
3170 if (old_map->is_prototype_map()) { | |
3171 DCHECK(!old_map->is_stable()); | |
3172 DCHECK(new_map->is_stable()); | |
3173 // Clear out the old descriptor array to avoid problems to sharing | |
3174 // the descriptor array without using an explicit. | |
3175 old_map->InitializeDescriptors( | |
3176 old_map->GetHeap()->empty_descriptor_array(), | |
3177 LayoutDescriptor::FastPointerLayout()); | |
3178 // Ensure that no transition was inserted for prototype migrations. | |
3179 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( | |
3180 old_map->raw_transitions())); | |
3181 DCHECK(new_map->GetBackPointer()->IsUndefined()); | |
3182 } | |
3183 } else { | |
3184 MigrateFastToSlow(object, new_map, expected_additional_properties); | |
3185 } | |
3186 } else { | |
3187 // For slow-to-fast migrations JSObject::MigrateSlowToFast() | 3168 // For slow-to-fast migrations JSObject::MigrateSlowToFast() |
3188 // must be used instead. | 3169 // must be used instead. |
3189 CHECK(new_map->is_dictionary_map()); | 3170 CHECK(new_map->is_dictionary_map()); |
3190 | 3171 |
3191 // Slow-to-slow migration is trivial. | 3172 // Slow-to-slow migration is trivial. |
3192 object->set_map(*new_map); | 3173 object->set_map(*new_map); |
| 3174 } else if (!new_map->is_dictionary_map()) { |
| 3175 MigrateFastToFast(object, new_map); |
| 3176 if (old_map->is_prototype_map()) { |
| 3177 DCHECK(!old_map->is_stable()); |
| 3178 DCHECK(new_map->is_stable()); |
| 3179 // Clear out the old descriptor array to avoid problems to sharing |
| 3180 // the descriptor array without using an explicit. |
| 3181 old_map->InitializeDescriptors( |
| 3182 old_map->GetHeap()->empty_descriptor_array(), |
| 3183 LayoutDescriptor::FastPointerLayout()); |
| 3184 // Ensure that no transition was inserted for prototype migrations. |
| 3185 DCHECK_EQ( |
| 3186 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions())); |
| 3187 DCHECK(new_map->GetBackPointer()->IsUndefined()); |
| 3188 } |
| 3189 } else { |
| 3190 MigrateFastToSlow(object, new_map, expected_additional_properties); |
3193 } | 3191 } |
3194 | 3192 |
3195 // Careful: Don't allocate here! | 3193 // Careful: Don't allocate here! |
3196 // For some callers of this method, |object| might be in an inconsistent | 3194 // For some callers of this method, |object| might be in an inconsistent |
3197 // state now: the new map might have a new elements_kind, but the object's | 3195 // state now: the new map might have a new elements_kind, but the object's |
3198 // elements pointer hasn't been updated yet. Callers will fix this, but in | 3196 // elements pointer hasn't been updated yet. Callers will fix this, but in |
3199 // the meantime, (indirectly) calling JSObjectVerify() must be avoided. | 3197 // the meantime, (indirectly) calling JSObjectVerify() must be avoided. |
3200 // When adding code here, add a DisallowHeapAllocation too. | 3198 // When adding code here, add a DisallowHeapAllocation too. |
3201 } | 3199 } |
3202 | 3200 |
(...skipping 1398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4601 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state()); | 4599 DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state()); |
4602 | 4600 |
4603 Handle<JSObject> receiver = it->GetStoreTarget(); | 4601 Handle<JSObject> receiver = it->GetStoreTarget(); |
4604 | 4602 |
4605 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) | 4603 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) |
4606 // instead. If the prototype is Null, the proxy is detached. | 4604 // instead. If the prototype is Null, the proxy is detached. |
4607 if (receiver->IsJSGlobalProxy()) return Just(true); | 4605 if (receiver->IsJSGlobalProxy()) return Just(true); |
4608 | 4606 |
4609 Isolate* isolate = it->isolate(); | 4607 Isolate* isolate = it->isolate(); |
4610 | 4608 |
4611 if (!receiver->map()->is_extensible() && | 4609 if (it->ExtendingNonExtensible(receiver)) { |
4612 (it->IsElement() || !isolate->IsInternallyUsedPropertyName(it->name()))) { | |
4613 RETURN_FAILURE( | 4610 RETURN_FAILURE( |
4614 isolate, should_throw, | 4611 isolate, should_throw, |
4615 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName())); | 4612 NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName())); |
4616 } | 4613 } |
4617 | 4614 |
4618 if (it->IsElement()) { | 4615 if (it->IsElement()) { |
4619 if (receiver->IsJSArray()) { | 4616 if (receiver->IsJSArray()) { |
4620 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 4617 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
4621 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) { | 4618 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) { |
4622 RETURN_FAILURE(array->GetIsolate(), should_throw, | 4619 RETURN_FAILURE(array->GetIsolate(), should_throw, |
(...skipping 12 matching lines...) Expand all Loading... |
4635 } | 4632 } |
4636 } | 4633 } |
4637 | 4634 |
4638 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value, | 4635 Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value, |
4639 attributes, should_throw); | 4636 attributes, should_throw); |
4640 JSObject::ValidateElements(receiver); | 4637 JSObject::ValidateElements(receiver); |
4641 return result; | 4638 return result; |
4642 } else { | 4639 } else { |
4643 // Migrate to the most up-to-date map that will be able to store |value| | 4640 // Migrate to the most up-to-date map that will be able to store |value| |
4644 // under it->name() with |attributes|. | 4641 // under it->name() with |attributes|. |
4645 it->PrepareTransitionToDataProperty(value, attributes, store_mode); | 4642 it->PrepareTransitionToDataProperty(receiver, value, attributes, |
| 4643 store_mode); |
4646 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); | 4644 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); |
4647 it->ApplyTransitionToDataProperty(); | 4645 it->ApplyTransitionToDataProperty(receiver); |
4648 | 4646 |
4649 // TODO(verwaest): Encapsulate dictionary handling better. | 4647 // TODO(verwaest): Encapsulate dictionary handling better. |
4650 if (receiver->map()->is_dictionary_map()) { | 4648 if (receiver->map()->is_dictionary_map()) { |
4651 // TODO(verwaest): Probably should ensure this is done beforehand. | 4649 // TODO(verwaest): Probably should ensure this is done beforehand. |
4652 it->InternalizeName(); | 4650 it->InternalizeName(); |
4653 // TODO(dcarney): just populate TransitionPropertyCell here? | 4651 // TODO(dcarney): just populate TransitionPropertyCell here? |
4654 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); | 4652 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); |
4655 } else { | 4653 } else { |
4656 // Write the property value. | 4654 // Write the property value. |
4657 it->WriteDataValue(value); | 4655 it->WriteDataValue(value); |
(...skipping 5265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9923 | 9921 |
9924 case ACCESSOR: | 9922 case ACCESSOR: |
9925 case ACCESSOR_CONSTANT: | 9923 case ACCESSOR_CONSTANT: |
9926 return false; | 9924 return false; |
9927 } | 9925 } |
9928 | 9926 |
9929 UNREACHABLE(); | 9927 UNREACHABLE(); |
9930 return false; | 9928 return false; |
9931 } | 9929 } |
9932 | 9930 |
| 9931 namespace { |
| 9932 |
| 9933 Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor, |
| 9934 Handle<Object> value) { |
| 9935 if (map->instance_descriptors()->CanHoldValue(descriptor, *value)) return map; |
| 9936 |
| 9937 Isolate* isolate = map->GetIsolate(); |
| 9938 PropertyAttributes attributes = |
| 9939 map->instance_descriptors()->GetDetails(descriptor).attributes(); |
| 9940 Representation representation = value->OptimalRepresentation(); |
| 9941 Handle<FieldType> type = value->OptimalType(isolate, representation); |
| 9942 |
| 9943 return Map::ReconfigureProperty(map, descriptor, kData, attributes, |
| 9944 representation, type, FORCE_FIELD); |
| 9945 } |
| 9946 |
| 9947 } // namespace |
9933 | 9948 |
9934 // static | 9949 // static |
9935 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, | 9950 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, |
9936 Handle<Object> value) { | 9951 Handle<Object> value) { |
9937 // Dictionaries can store any property value. | 9952 // Dictionaries can store any property value. |
9938 if (map->is_dictionary_map()) return map; | 9953 if (map->is_dictionary_map()) return map; |
9939 | 9954 |
9940 // Migrate to the newest map before storing the property. | 9955 // Update to the newest map before storing the property. |
9941 map = Update(map); | 9956 return UpdateDescriptorForValue(Update(map), descriptor, value); |
9942 | |
9943 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | |
9944 | |
9945 if (descriptors->CanHoldValue(descriptor, *value)) return map; | |
9946 | |
9947 Isolate* isolate = map->GetIsolate(); | |
9948 PropertyAttributes attributes = | |
9949 descriptors->GetDetails(descriptor).attributes(); | |
9950 Representation representation = value->OptimalRepresentation(); | |
9951 Handle<FieldType> type = value->OptimalType(isolate, representation); | |
9952 | |
9953 return ReconfigureProperty(map, descriptor, kData, attributes, representation, | |
9954 type, FORCE_FIELD); | |
9955 } | 9957 } |
9956 | 9958 |
9957 | 9959 |
9958 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, | 9960 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, |
9959 Handle<Object> value, | 9961 Handle<Object> value, |
9960 PropertyAttributes attributes, | 9962 PropertyAttributes attributes, |
9961 StoreFromKeyed store_mode) { | 9963 StoreFromKeyed store_mode) { |
9962 // Dictionary maps can always have additional data properties. | 9964 // Dictionary maps can always have additional data properties. |
9963 if (map->is_dictionary_map()) return map; | 9965 if (map->is_dictionary_map()) return map; |
9964 | 9966 |
9965 // Migrate to the newest map before storing the property. | 9967 // Migrate to the newest map before storing the property. |
9966 map = Update(map); | 9968 map = Update(map); |
9967 | 9969 |
9968 Map* maybe_transition = | 9970 Map* maybe_transition = |
9969 TransitionArray::SearchTransition(*map, kData, *name, attributes); | 9971 TransitionArray::SearchTransition(*map, kData, *name, attributes); |
9970 if (maybe_transition != NULL) { | 9972 if (maybe_transition != NULL) { |
9971 Handle<Map> transition(maybe_transition); | 9973 Handle<Map> transition(maybe_transition); |
9972 int descriptor = transition->LastAdded(); | 9974 int descriptor = transition->LastAdded(); |
9973 | 9975 |
9974 DCHECK_EQ(attributes, transition->instance_descriptors() | 9976 DCHECK_EQ(attributes, transition->instance_descriptors() |
9975 ->GetDetails(descriptor) | 9977 ->GetDetails(descriptor) |
9976 .attributes()); | 9978 .attributes()); |
9977 | 9979 |
9978 return Map::PrepareForDataProperty(transition, descriptor, value); | 9980 return UpdateDescriptorForValue(transition, descriptor, value); |
9979 } | 9981 } |
9980 | 9982 |
9981 TransitionFlag flag = INSERT_TRANSITION; | 9983 TransitionFlag flag = INSERT_TRANSITION; |
9982 MaybeHandle<Map> maybe_map; | 9984 MaybeHandle<Map> maybe_map; |
9983 if (value->IsJSFunction()) { | 9985 if (value->IsJSFunction()) { |
9984 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag); | 9986 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag); |
9985 } else if (!map->TooManyFastProperties(store_mode)) { | 9987 } else if (!map->TooManyFastProperties(store_mode)) { |
9986 Isolate* isolate = name->GetIsolate(); | 9988 Isolate* isolate = name->GetIsolate(); |
9987 Representation representation = value->OptimalRepresentation(); | 9989 Representation representation = value->OptimalRepresentation(); |
9988 Handle<FieldType> type = value->OptimalType(isolate, representation); | 9990 Handle<FieldType> type = value->OptimalType(isolate, representation); |
(...skipping 9994 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19983 if (cell->value() != *new_value) { | 19985 if (cell->value() != *new_value) { |
19984 cell->set_value(*new_value); | 19986 cell->set_value(*new_value); |
19985 Isolate* isolate = cell->GetIsolate(); | 19987 Isolate* isolate = cell->GetIsolate(); |
19986 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 19988 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
19987 isolate, DependentCode::kPropertyCellChangedGroup); | 19989 isolate, DependentCode::kPropertyCellChangedGroup); |
19988 } | 19990 } |
19989 } | 19991 } |
19990 | 19992 |
19991 } // namespace internal | 19993 } // namespace internal |
19992 } // namespace v8 | 19994 } // namespace v8 |
OLD | NEW |