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 4403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4414 // properties. | 4414 // properties. |
4415 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | 4415 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
4416 | 4416 |
4417 // Store on the holder which may be hidden behind the receiver. | 4417 // Store on the holder which may be hidden behind the receiver. |
4418 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); | 4418 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); |
4419 | 4419 |
4420 // Old value for the observation change record. | 4420 // Old value for the observation change record. |
4421 // Fetch before transforming the object since the encoding may become | 4421 // Fetch before transforming the object since the encoding may become |
4422 // incompatible with what's cached in |it|. | 4422 // incompatible with what's cached in |it|. |
4423 bool is_observed = receiver->map()->is_observed() && | 4423 bool is_observed = receiver->map()->is_observed() && |
4424 (it->IsElement() || | 4424 (it->IsElement() || !it->name()->IsPrivate()); |
4425 !it->isolate()->IsInternallyUsedPropertyName(it->name())); | |
4426 MaybeHandle<Object> maybe_old; | 4425 MaybeHandle<Object> maybe_old; |
4427 if (is_observed) maybe_old = it->GetDataValue(); | 4426 if (is_observed) maybe_old = it->GetDataValue(); |
4428 | 4427 |
4429 Handle<Object> to_assign = value; | 4428 Handle<Object> to_assign = value; |
4430 // Convert the incoming value to a number for storing into typed arrays. | 4429 // Convert the incoming value to a number for storing into typed arrays. |
4431 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) { | 4430 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) { |
4432 if (!value->IsNumber() && !value->IsUndefined()) { | 4431 if (!value->IsNumber() && !value->IsUndefined()) { |
4433 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 4432 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
4434 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>()); | 4433 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>()); |
4435 // We have to recheck the length. However, it can only change if the | 4434 // We have to recheck the length. However, it can only change if the |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4570 // TODO(verwaest): Probably should ensure this is done beforehand. | 4569 // TODO(verwaest): Probably should ensure this is done beforehand. |
4571 it->InternalizeName(); | 4570 it->InternalizeName(); |
4572 // TODO(dcarney): just populate TransitionPropertyCell here? | 4571 // TODO(dcarney): just populate TransitionPropertyCell here? |
4573 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); | 4572 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); |
4574 } else { | 4573 } else { |
4575 // Write the property value. | 4574 // Write the property value. |
4576 it->WriteDataValue(value); | 4575 it->WriteDataValue(value); |
4577 } | 4576 } |
4578 | 4577 |
4579 // Send the change record if there are observers. | 4578 // Send the change record if there are observers. |
4580 if (receiver->map()->is_observed() && | 4579 if (receiver->map()->is_observed() && !it->name()->IsPrivate()) { |
4581 !isolate->IsInternallyUsedPropertyName(it->name())) { | |
4582 RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord( | 4580 RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord( |
4583 receiver, "add", it->name(), | 4581 receiver, "add", it->name(), |
4584 it->factory()->the_hole_value()), | 4582 it->factory()->the_hole_value()), |
4585 Nothing<bool>()); | 4583 Nothing<bool>()); |
4586 } | 4584 } |
4587 #if VERIFY_HEAP | 4585 #if VERIFY_HEAP |
4588 if (FLAG_verify_heap) { | 4586 if (FLAG_verify_heap) { |
4589 receiver->JSObjectVerify(); | 4587 receiver->JSObjectVerify(); |
4590 } | 4588 } |
4591 #endif | 4589 #endif |
(...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5272 PropertyAttributes attributes) { | 5270 PropertyAttributes attributes) { |
5273 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); | 5271 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); |
5274 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); | 5272 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); |
5275 #ifdef DEBUG | 5273 #ifdef DEBUG |
5276 uint32_t index; | 5274 uint32_t index; |
5277 DCHECK(!object->IsJSProxy()); | 5275 DCHECK(!object->IsJSProxy()); |
5278 DCHECK(!name->AsArrayIndex(&index)); | 5276 DCHECK(!name->AsArrayIndex(&index)); |
5279 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); | 5277 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); |
5280 DCHECK(maybe.IsJust()); | 5278 DCHECK(maybe.IsJust()); |
5281 DCHECK(!it.IsFound()); | 5279 DCHECK(!it.IsFound()); |
5282 DCHECK(object->map()->is_extensible() || | 5280 DCHECK(object->map()->is_extensible() || name->IsPrivate()); |
5283 it.isolate()->IsInternallyUsedPropertyName(name)); | |
5284 #endif | 5281 #endif |
5285 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR, | 5282 CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR, |
5286 CERTAINLY_NOT_STORE_FROM_KEYED) | 5283 CERTAINLY_NOT_STORE_FROM_KEYED) |
5287 .IsJust()); | 5284 .IsJust()); |
5288 } | 5285 } |
5289 | 5286 |
5290 | 5287 |
5291 // Reconfigures a property to a data property with attributes, even if it is not | 5288 // Reconfigures a property to a data property with attributes, even if it is not |
5292 // reconfigurable. | 5289 // reconfigurable. |
5293 // Requires a LookupIterator that does not look at the prototype chain beyond | 5290 // Requires a LookupIterator that does not look at the prototype chain beyond |
5294 // hidden prototypes. | 5291 // hidden prototypes. |
5295 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes( | 5292 MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes( |
5296 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, | 5293 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, |
5297 AccessorInfoHandling handling) { | 5294 AccessorInfoHandling handling) { |
5298 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes( | 5295 MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes( |
5299 it, value, attributes, THROW_ON_ERROR, handling)); | 5296 it, value, attributes, THROW_ON_ERROR, handling)); |
5300 return value; | 5297 return value; |
5301 } | 5298 } |
5302 | 5299 |
5303 | 5300 |
5304 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( | 5301 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( |
5305 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, | 5302 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, |
5306 ShouldThrow should_throw, AccessorInfoHandling handling) { | 5303 ShouldThrow should_throw, AccessorInfoHandling handling) { |
5307 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); | 5304 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); |
5308 bool is_observed = object->map()->is_observed() && | 5305 bool is_observed = object->map()->is_observed() && |
5309 (it->IsElement() || | 5306 (it->IsElement() || !it->name()->IsPrivate()); |
5310 !it->isolate()->IsInternallyUsedPropertyName(it->name())); | |
5311 | 5307 |
5312 for (; it->IsFound(); it->Next()) { | 5308 for (; it->IsFound(); it->Next()) { |
5313 switch (it->state()) { | 5309 switch (it->state()) { |
5314 case LookupIterator::JSPROXY: | 5310 case LookupIterator::JSPROXY: |
5315 case LookupIterator::NOT_FOUND: | 5311 case LookupIterator::NOT_FOUND: |
5316 case LookupIterator::TRANSITION: | 5312 case LookupIterator::TRANSITION: |
5317 UNREACHABLE(); | 5313 UNREACHABLE(); |
5318 | 5314 |
5319 case LookupIterator::ACCESS_CHECK: | 5315 case LookupIterator::ACCESS_CHECK: |
5320 if (!it->HasAccess()) { | 5316 if (!it->HasAccess()) { |
(...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6027 | 6023 |
6028 if (inline_value->IsUndefined()) return; | 6024 if (inline_value->IsUndefined()) return; |
6029 | 6025 |
6030 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value)); | 6026 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value)); |
6031 bool was_present = false; | 6027 bool was_present = false; |
6032 ObjectHashTable::Remove(hashtable, key, &was_present); | 6028 ObjectHashTable::Remove(hashtable, key, &was_present); |
6033 } | 6029 } |
6034 | 6030 |
6035 | 6031 |
6036 bool JSObject::HasHiddenProperties(Handle<JSObject> object) { | 6032 bool JSObject::HasHiddenProperties(Handle<JSObject> object) { |
6037 Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string(); | 6033 Isolate* isolate = object->GetIsolate(); |
6038 LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR); | 6034 Handle<Symbol> hidden = isolate->factory()->hidden_properties_symbol(); |
| 6035 LookupIterator it(object, hidden); |
6039 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); | 6036 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); |
6040 // Cannot get an exception since the hidden_string isn't accessible to JS. | 6037 // Cannot get an exception since the hidden_properties_symbol isn't exposed to |
| 6038 // JS. |
6041 DCHECK(maybe.IsJust()); | 6039 DCHECK(maybe.IsJust()); |
6042 return maybe.FromJust() != ABSENT; | 6040 return maybe.FromJust() != ABSENT; |
6043 } | 6041 } |
6044 | 6042 |
6045 | 6043 |
6046 Object* JSObject::GetHiddenPropertiesHashTable() { | 6044 Object* JSObject::GetHiddenPropertiesHashTable() { |
6047 DCHECK(!IsJSGlobalProxy()); | 6045 DCHECK(!IsJSGlobalProxy()); |
6048 if (HasFastProperties()) { | 6046 if (HasFastProperties()) { |
6049 // If the object has fast properties, check whether the first slot | 6047 // If the object has fast properties, check whether the first slot |
6050 // in the descriptor array matches the hidden string. Since the | 6048 // in the descriptor array matches the hidden string. Since the |
6051 // hidden strings hash code is zero (and no other name has hash | 6049 // hidden strings hash code is zero (and no other name has hash |
6052 // code zero) it will always occupy the first entry if present. | 6050 // code zero) it will always occupy the first entry if present. |
6053 DescriptorArray* descriptors = this->map()->instance_descriptors(); | 6051 DescriptorArray* descriptors = this->map()->instance_descriptors(); |
6054 if (descriptors->number_of_descriptors() > 0) { | 6052 if (descriptors->number_of_descriptors() > 0) { |
6055 int sorted_index = descriptors->GetSortedKeyIndex(0); | 6053 int sorted_index = descriptors->GetSortedKeyIndex(0); |
6056 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() && | 6054 if (descriptors->GetKey(sorted_index) == |
| 6055 GetHeap()->hidden_properties_symbol() && |
6057 sorted_index < map()->NumberOfOwnDescriptors()) { | 6056 sorted_index < map()->NumberOfOwnDescriptors()) { |
6058 DCHECK(descriptors->GetType(sorted_index) == DATA); | 6057 DCHECK(descriptors->GetType(sorted_index) == DATA); |
6059 DCHECK(descriptors->GetDetails(sorted_index).representation(). | 6058 DCHECK(descriptors->GetDetails(sorted_index).representation(). |
6060 IsCompatibleForLoad(Representation::Tagged())); | 6059 IsCompatibleForLoad(Representation::Tagged())); |
6061 FieldIndex index = FieldIndex::ForDescriptor(this->map(), | 6060 FieldIndex index = FieldIndex::ForDescriptor(this->map(), |
6062 sorted_index); | 6061 sorted_index); |
6063 return this->RawFastPropertyAt(index); | 6062 return this->RawFastPropertyAt(index); |
6064 } else { | 6063 } else { |
6065 return GetHeap()->undefined_value(); | 6064 return GetHeap()->undefined_value(); |
6066 } | 6065 } |
6067 } else { | 6066 } else { |
6068 return GetHeap()->undefined_value(); | 6067 return GetHeap()->undefined_value(); |
6069 } | 6068 } |
6070 } else { | 6069 } else { |
6071 Isolate* isolate = GetIsolate(); | 6070 Handle<Symbol> hidden = GetIsolate()->factory()->hidden_properties_symbol(); |
6072 LookupIterator it(handle(this), isolate->factory()->hidden_string(), | 6071 LookupIterator it(handle(this), hidden); |
6073 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
6074 // Access check is always skipped for the hidden string anyways. | 6072 // Access check is always skipped for the hidden string anyways. |
6075 return *GetDataProperty(&it); | 6073 return *GetDataProperty(&it); |
6076 } | 6074 } |
6077 } | 6075 } |
6078 | 6076 |
6079 Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable( | 6077 Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable( |
6080 Handle<JSObject> object) { | 6078 Handle<JSObject> object) { |
6081 Isolate* isolate = object->GetIsolate(); | 6079 Isolate* isolate = object->GetIsolate(); |
6082 | 6080 |
6083 static const int kInitialCapacity = 4; | 6081 static const int kInitialCapacity = 4; |
6084 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate); | 6082 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate); |
6085 if (inline_value->IsHashTable()) { | 6083 if (inline_value->IsHashTable()) { |
6086 return Handle<ObjectHashTable>::cast(inline_value); | 6084 return Handle<ObjectHashTable>::cast(inline_value); |
6087 } | 6085 } |
6088 | 6086 |
6089 Handle<ObjectHashTable> hashtable = ObjectHashTable::New( | 6087 Handle<ObjectHashTable> hashtable = ObjectHashTable::New( |
6090 isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY); | 6088 isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY); |
6091 | 6089 |
6092 DCHECK(inline_value->IsUndefined()); | 6090 DCHECK(inline_value->IsUndefined()); |
6093 SetHiddenPropertiesHashTable(object, hashtable); | 6091 SetHiddenPropertiesHashTable(object, hashtable); |
6094 return hashtable; | 6092 return hashtable; |
6095 } | 6093 } |
6096 | 6094 |
6097 | 6095 |
6098 Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object, | 6096 Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object, |
6099 Handle<Object> value) { | 6097 Handle<Object> value) { |
6100 DCHECK(!object->IsJSGlobalProxy()); | 6098 DCHECK(!object->IsJSGlobalProxy()); |
6101 Isolate* isolate = object->GetIsolate(); | 6099 Isolate* isolate = object->GetIsolate(); |
6102 Handle<Name> name = isolate->factory()->hidden_string(); | 6100 Handle<Symbol> name = isolate->factory()->hidden_properties_symbol(); |
6103 SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert(); | 6101 SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert(); |
6104 return object; | 6102 return object; |
6105 } | 6103 } |
6106 | 6104 |
6107 | 6105 |
6108 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it, | 6106 Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it, |
6109 ShouldThrow should_throw) { | 6107 ShouldThrow should_throw) { |
6110 Isolate* isolate = it->isolate(); | 6108 Isolate* isolate = it->isolate(); |
6111 // Make sure that the top context does not change when doing callbacks or | 6109 // Make sure that the top context does not change when doing callbacks or |
6112 // interceptor calls. | 6110 // interceptor calls. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6192 if (it->GetReceiver()->IsJSProxy()) { | 6190 if (it->GetReceiver()->IsJSProxy()) { |
6193 if (it->state() != LookupIterator::NOT_FOUND) { | 6191 if (it->state() != LookupIterator::NOT_FOUND) { |
6194 DCHECK_EQ(LookupIterator::DATA, it->state()); | 6192 DCHECK_EQ(LookupIterator::DATA, it->state()); |
6195 DCHECK(it->GetName()->IsPrivate()); | 6193 DCHECK(it->GetName()->IsPrivate()); |
6196 it->Delete(); | 6194 it->Delete(); |
6197 } | 6195 } |
6198 return Just(true); | 6196 return Just(true); |
6199 } | 6197 } |
6200 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | 6198 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
6201 | 6199 |
6202 bool is_observed = | 6200 bool is_observed = receiver->map()->is_observed() && |
6203 receiver->map()->is_observed() && | 6201 (it->IsElement() || !it->name()->IsPrivate()); |
6204 (it->IsElement() || !isolate->IsInternallyUsedPropertyName(it->name())); | |
6205 | 6202 |
6206 Handle<Object> old_value = it->factory()->the_hole_value(); | 6203 Handle<Object> old_value = it->factory()->the_hole_value(); |
6207 | 6204 |
6208 for (; it->IsFound(); it->Next()) { | 6205 for (; it->IsFound(); it->Next()) { |
6209 switch (it->state()) { | 6206 switch (it->state()) { |
6210 case LookupIterator::JSPROXY: | 6207 case LookupIterator::JSPROXY: |
6211 case LookupIterator::NOT_FOUND: | 6208 case LookupIterator::NOT_FOUND: |
6212 case LookupIterator::TRANSITION: | 6209 case LookupIterator::TRANSITION: |
6213 UNREACHABLE(); | 6210 UNREACHABLE(); |
6214 case LookupIterator::ACCESS_CHECK: | 6211 case LookupIterator::ACCESS_CHECK: |
(...skipping 2837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9052 } | 9049 } |
9053 | 9050 |
9054 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); | 9051 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); |
9055 // Ignore accessors on typed arrays. | 9052 // Ignore accessors on typed arrays. |
9056 if (it->IsElement() && object->HasFixedTypedArrayElements()) { | 9053 if (it->IsElement() && object->HasFixedTypedArrayElements()) { |
9057 return it->factory()->undefined_value(); | 9054 return it->factory()->undefined_value(); |
9058 } | 9055 } |
9059 | 9056 |
9060 Handle<Object> old_value = isolate->factory()->the_hole_value(); | 9057 Handle<Object> old_value = isolate->factory()->the_hole_value(); |
9061 bool is_observed = object->map()->is_observed() && | 9058 bool is_observed = object->map()->is_observed() && |
9062 !isolate->IsInternallyUsedPropertyName(it->GetName()); | 9059 (it->IsElement() || !it->name()->IsPrivate()); |
9063 bool preexists = false; | 9060 bool preexists = false; |
9064 if (is_observed) { | 9061 if (is_observed) { |
9065 CHECK(GetPropertyAttributes(it).IsJust()); | 9062 CHECK(GetPropertyAttributes(it).IsJust()); |
9066 preexists = it->IsFound(); | 9063 preexists = it->IsFound(); |
9067 if (preexists && (it->state() == LookupIterator::DATA || | 9064 if (preexists && (it->state() == LookupIterator::DATA || |
9068 it->GetAccessors()->IsAccessorInfo())) { | 9065 it->GetAccessors()->IsAccessorInfo())) { |
9069 old_value = GetProperty(it).ToHandleChecked(); | 9066 old_value = GetProperty(it).ToHandleChecked(); |
9070 } | 9067 } |
9071 } | 9068 } |
9072 | 9069 |
(...skipping 10840 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19913 if (cell->value() != *new_value) { | 19910 if (cell->value() != *new_value) { |
19914 cell->set_value(*new_value); | 19911 cell->set_value(*new_value); |
19915 Isolate* isolate = cell->GetIsolate(); | 19912 Isolate* isolate = cell->GetIsolate(); |
19916 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 19913 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
19917 isolate, DependentCode::kPropertyCellChangedGroup); | 19914 isolate, DependentCode::kPropertyCellChangedGroup); |
19918 } | 19915 } |
19919 } | 19916 } |
19920 | 19917 |
19921 } // namespace internal | 19918 } // namespace internal |
19922 } // namespace v8 | 19919 } // namespace v8 |
OLD | NEW |