diff options
Diffstat (limited to 'deps/v8/src/lookup.cc')
-rw-r--r-- | deps/v8/src/lookup.cc | 263 |
1 files changed, 152 insertions, 111 deletions
diff --git a/deps/v8/src/lookup.cc b/deps/v8/src/lookup.cc index 967ce498ac..b855abe97f 100644 --- a/deps/v8/src/lookup.cc +++ b/deps/v8/src/lookup.cc @@ -5,6 +5,7 @@ #include "src/v8.h" #include "src/bootstrapper.h" +#include "src/deoptimizer.h" #include "src/lookup.h" #include "src/lookup-inl.h" @@ -13,46 +14,56 @@ namespace internal { void LookupIterator::Next() { + DCHECK_NE(JSPROXY, state_); + DCHECK_NE(TRANSITION, state_); DisallowHeapAllocation no_gc; has_property_ = false; - JSReceiver* holder = NULL; + JSReceiver* holder = *holder_; Map* map = *holder_map_; // Perform lookup on current holder. - state_ = LookupInHolder(map); + state_ = LookupInHolder(map, holder); + if (IsFound()) return; // Continue lookup if lookup on current holder failed. - while (!IsFound()) { + do { JSReceiver* maybe_holder = NextHolder(map); if (maybe_holder == NULL) break; holder = maybe_holder; map = holder->map(); - state_ = LookupInHolder(map); - } + state_ = LookupInHolder(map, holder); + } while (!IsFound()); - // Either was found in the receiver, or the receiver has no prototype. - if (holder == NULL) return; - - maybe_holder_ = handle(holder); - holder_map_ = handle(map); + if (holder != *holder_) { + holder_ = handle(holder, isolate_); + holder_map_ = handle(map, isolate_); + } } Handle<JSReceiver> LookupIterator::GetRoot() const { - Handle<Object> receiver = GetReceiver(); - if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); + if (receiver_->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver_); Handle<Object> root = - handle(receiver->GetRootMap(isolate_)->prototype(), isolate_); + handle(receiver_->GetRootMap(isolate_)->prototype(), isolate_); CHECK(!root->IsNull()); return Handle<JSReceiver>::cast(root); } Handle<Map> LookupIterator::GetReceiverMap() const { - Handle<Object> receiver = GetReceiver(); - if (receiver->IsNumber()) return isolate_->factory()->heap_number_map(); - return handle(Handle<HeapObject>::cast(receiver)->map()); + if (receiver_->IsNumber()) return isolate_->factory()->heap_number_map(); + return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); +} + + +Handle<JSObject> LookupIterator::GetStoreTarget() const { + if (receiver_->IsJSGlobalProxy()) { + PrototypeIterator iter(isolate(), receiver_); + if (iter.IsAtEnd()) return Handle<JSGlobalProxy>::cast(receiver_); + return Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); + } + return Handle<JSObject>::cast(receiver_); } @@ -63,110 +74,137 @@ bool LookupIterator::IsBootstrapping() const { bool LookupIterator::HasAccess(v8::AccessType access_type) const { DCHECK_EQ(ACCESS_CHECK, state_); - DCHECK(is_guaranteed_to_have_holder()); return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type); } -bool LookupIterator::HasProperty() { - DCHECK_EQ(PROPERTY, state_); - DCHECK(is_guaranteed_to_have_holder()); - - if (property_encoding_ == DICTIONARY) { - Handle<JSObject> holder = GetHolder<JSObject>(); - number_ = holder->property_dictionary()->FindEntry(name_); - if (number_ == NameDictionary::kNotFound) return false; - - property_details_ = holder->property_dictionary()->DetailsAt(number_); - // Holes in dictionary cells are absent values. - if (holder->IsGlobalObject() && - (property_details_.IsDeleted() || FetchValue()->IsTheHole())) { - return false; - } - } else { - // Can't use descriptor_number() yet because has_property_ is still false. - property_details_ = - holder_map_->instance_descriptors()->GetDetails(number_); - } - - switch (property_details_.type()) { - case v8::internal::FIELD: - case v8::internal::NORMAL: - case v8::internal::CONSTANT: - property_kind_ = DATA; - break; - case v8::internal::CALLBACKS: - property_kind_ = ACCESSOR; - break; - case v8::internal::HANDLER: - case v8::internal::NONEXISTENT: - case v8::internal::INTERCEPTOR: - UNREACHABLE(); - } - - has_property_ = true; - return true; +void LookupIterator::ReloadPropertyInformation() { + state_ = BEFORE_PROPERTY; + state_ = LookupInHolder(*holder_map_, *holder_); + DCHECK(IsFound() || holder_map_->is_dictionary_map()); } void LookupIterator::PrepareForDataProperty(Handle<Object> value) { - DCHECK(has_property_); + DCHECK(state_ == DATA || state_ == ACCESSOR); DCHECK(HolderIsReceiverOrHiddenPrototype()); - if (property_encoding_ == DICTIONARY) return; + if (holder_map_->is_dictionary_map()) return; holder_map_ = Map::PrepareForDataProperty(holder_map_, descriptor_number(), value); JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_); - // Reload property information. + ReloadPropertyInformation(); +} + + +void LookupIterator::ReconfigureDataProperty(Handle<Object> value, + PropertyAttributes attributes) { + DCHECK(state_ == DATA || state_ == ACCESSOR); + DCHECK(HolderIsReceiverOrHiddenPrototype()); + Handle<JSObject> holder = GetHolder<JSObject>(); if (holder_map_->is_dictionary_map()) { - property_encoding_ = DICTIONARY; + PropertyDetails details(attributes, NORMAL, 0); + JSObject::SetNormalizedProperty(holder, name(), value, details); } else { - property_encoding_ = DESCRIPTOR; + holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(), + attributes); + JSObject::MigrateToMap(holder, holder_map_); } - CHECK(HasProperty()); + + ReloadPropertyInformation(); } -void LookupIterator::TransitionToDataProperty( +void LookupIterator::PrepareTransitionToDataProperty( Handle<Object> value, PropertyAttributes attributes, Object::StoreFromKeyed store_mode) { - DCHECK(!has_property_ || !HolderIsReceiverOrHiddenPrototype()); + if (state_ == TRANSITION) return; + DCHECK(state_ != LookupIterator::ACCESSOR || + GetAccessors()->IsDeclaredAccessorInfo()); + DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype()); // Can only be called when the receiver is a JSObject. JSProxy has to be // handled via a trap. Adding properties to primitive values is not // observable. - Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver()); - - // Properties have to be added to context extension objects through - // SetOwnPropertyIgnoreAttributes. - DCHECK(!receiver->IsJSContextExtensionObject()); + Handle<JSObject> receiver = GetStoreTarget(); - if (receiver->IsJSGlobalProxy()) { - PrototypeIterator iter(isolate(), receiver); - receiver = - Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)); + if (!name().is_identical_to(isolate()->factory()->hidden_string()) && + !receiver->map()->is_extensible()) { + return; } - maybe_holder_ = receiver; - holder_map_ = Map::TransitionToDataProperty(handle(receiver->map()), name_, - value, attributes, store_mode); + transition_map_ = Map::TransitionToDataProperty( + handle(receiver->map(), isolate_), name_, value, attributes, store_mode); + state_ = TRANSITION; +} + + +void LookupIterator::ApplyTransitionToDataProperty() { + DCHECK_EQ(TRANSITION, state_); + + Handle<JSObject> receiver = GetStoreTarget(); + holder_ = receiver; + holder_map_ = transition_map_; + JSObject::MigrateToMap(receiver, holder_map_); + ReloadPropertyInformation(); +} + + +void LookupIterator::TransitionToAccessorProperty( + AccessorComponent component, Handle<Object> accessor, + PropertyAttributes attributes) { + DCHECK(!accessor->IsNull()); + // Can only be called when the receiver is a JSObject. JSProxy has to be + // handled via a trap. Adding properties to primitive values is not + // observable. + Handle<JSObject> receiver = GetStoreTarget(); + holder_ = receiver; + holder_map_ = + Map::TransitionToAccessorProperty(handle(receiver->map(), isolate_), + name_, component, accessor, attributes); JSObject::MigrateToMap(receiver, holder_map_); - // Reload the information. - state_ = NOT_FOUND; - configuration_ = CHECK_OWN_REAL; - state_ = LookupInHolder(*holder_map_); - DCHECK(IsFound()); - HasProperty(); + ReloadPropertyInformation(); + + if (!holder_map_->is_dictionary_map()) return; + + // We have to deoptimize since accesses to data properties may have been + // inlined without a corresponding map-check. + if (holder_map_->IsGlobalObjectMap()) { + Deoptimizer::DeoptimizeGlobalObject(*receiver); + } + + // Install the accessor into the dictionary-mode object. + PropertyDetails details(attributes, CALLBACKS, 0); + Handle<AccessorPair> pair; + if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) { + pair = Handle<AccessorPair>::cast(GetAccessors()); + // If the component and attributes are identical, nothing has to be done. + if (pair->get(component) == *accessor) { + if (property_details().attributes() == attributes) return; + } else { + pair = AccessorPair::Copy(pair); + pair->set(component, *accessor); + } + } else { + pair = isolate()->factory()->NewAccessorPair(); + pair->set(component, *accessor); + } + JSObject::SetNormalizedProperty(receiver, name_, pair, details); + + JSObject::ReoptimizeIfPrototype(receiver); + holder_map_ = handle(receiver->map(), isolate_); + ReloadPropertyInformation(); } bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); + // Optimization that only works if configuration_ is not mutable. + if (!check_prototype_chain()) return true; DisallowHeapAllocation no_gc; - Handle<Object> receiver = GetReceiver(); - if (!receiver->IsJSReceiver()) return false; - Object* current = *receiver; - JSReceiver* holder = *maybe_holder_.ToHandleChecked(); + if (!receiver_->IsJSReceiver()) return false; + Object* current = *receiver_; + JSReceiver* holder = *holder_; // JSProxy do not occur as hidden prototypes. if (current->IsJSProxy()) { return JSReceiver::cast(current) == holder; @@ -185,21 +223,17 @@ bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { Handle<Object> LookupIterator::FetchValue() const { Object* result = NULL; Handle<JSObject> holder = GetHolder<JSObject>(); - switch (property_encoding_) { - case DICTIONARY: - result = holder->property_dictionary()->ValueAt(number_); - if (holder->IsGlobalObject()) { - result = PropertyCell::cast(result)->value(); - } - break; - case DESCRIPTOR: - if (property_details_.type() == v8::internal::FIELD) { - FieldIndex field_index = - FieldIndex::ForDescriptor(*holder_map_, number_); - return JSObject::FastPropertyAt( - holder, property_details_.representation(), field_index); - } - result = holder_map_->instance_descriptors()->GetValue(number_); + if (holder_map_->is_dictionary_map()) { + result = holder->property_dictionary()->ValueAt(number_); + if (holder_map_->IsGlobalObjectMap()) { + result = PropertyCell::cast(result)->value(); + } + } else if (property_details_.type() == v8::internal::FIELD) { + FieldIndex field_index = FieldIndex::ForDescriptor(*holder_map_, number_); + return JSObject::FastPropertyAt(holder, property_details_.representation(), + field_index); + } else { + result = holder_map_->instance_descriptors()->GetValue(number_); } return handle(result, isolate_); } @@ -207,7 +241,7 @@ Handle<Object> LookupIterator::FetchValue() const { int LookupIterator::GetConstantIndex() const { DCHECK(has_property_); - DCHECK_EQ(DESCRIPTOR, property_encoding_); + DCHECK(!holder_map_->is_dictionary_map()); DCHECK_EQ(v8::internal::CONSTANT, property_details_.type()); return descriptor_number(); } @@ -215,12 +249,22 @@ int LookupIterator::GetConstantIndex() const { FieldIndex LookupIterator::GetFieldIndex() const { DCHECK(has_property_); - DCHECK_EQ(DESCRIPTOR, property_encoding_); + DCHECK(!holder_map_->is_dictionary_map()); DCHECK_EQ(v8::internal::FIELD, property_details_.type()); int index = - holder_map()->instance_descriptors()->GetFieldIndex(descriptor_number()); + holder_map_->instance_descriptors()->GetFieldIndex(descriptor_number()); bool is_double = representation().IsDouble(); - return FieldIndex::ForPropertyIndex(*holder_map(), index, is_double); + return FieldIndex::ForPropertyIndex(*holder_map_, index, is_double); +} + + +Handle<HeapType> LookupIterator::GetFieldType() const { + DCHECK(has_property_); + DCHECK(!holder_map_->is_dictionary_map()); + DCHECK_EQ(v8::internal::FIELD, property_details_.type()); + return handle( + holder_map_->instance_descriptors()->GetFieldType(descriptor_number()), + isolate_); } @@ -233,25 +277,22 @@ Handle<PropertyCell> LookupIterator::GetPropertyCell() const { Handle<Object> LookupIterator::GetAccessors() const { - DCHECK(has_property_); - DCHECK_EQ(ACCESSOR, property_kind_); + DCHECK_EQ(ACCESSOR, state_); return FetchValue(); } Handle<Object> LookupIterator::GetDataValue() const { - DCHECK(has_property_); - DCHECK_EQ(DATA, property_kind_); + DCHECK_EQ(DATA, state_); Handle<Object> value = FetchValue(); return value; } void LookupIterator::WriteDataValue(Handle<Object> value) { - DCHECK(is_guaranteed_to_have_holder()); - DCHECK(has_property_); + DCHECK_EQ(DATA, state_); Handle<JSObject> holder = GetHolder<JSObject>(); - if (property_encoding_ == DICTIONARY) { + if (holder_map_->is_dictionary_map()) { NameDictionary* property_dictionary = holder->property_dictionary(); if (holder->IsGlobalObject()) { Handle<PropertyCell> cell( |