aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/lookup.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/lookup.cc')
-rw-r--r--deps/v8/src/lookup.cc263
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(