Flatten property_kind into state. Add UNKNOWN as a state for dict-mode receivers
BUG= R=yangguo@chromium.org Review URL: https://codereview.chromium.org/540903002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23692 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
0baf275e20
commit
3ef094402e
@ -181,7 +181,7 @@ void Accessors::ArgumentsIteratorSetter(
|
||||
if (SetPropertyOnInstanceIfInherited(isolate, info, name, value)) return;
|
||||
|
||||
LookupIterator it(object, Utils::OpenHandle(*name));
|
||||
CHECK(it.HasProperty());
|
||||
CHECK_EQ(LookupIterator::ACCESSOR, it.state());
|
||||
DCHECK(it.HolderIsReceiverOrHiddenPrototype());
|
||||
Object::SetDataProperty(&it, value);
|
||||
}
|
||||
|
@ -2488,7 +2488,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
LookupIterator it(to, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
||||
// If the property is already there we skip it
|
||||
if (it.IsFound() && it.HasProperty()) continue;
|
||||
if (it.IsFound()) continue;
|
||||
HandleScope inner(isolate());
|
||||
DCHECK(!to->HasFastProperties());
|
||||
// Add to dictionary.
|
||||
@ -2516,7 +2516,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
Handle<Name> key(Name::cast(raw_key));
|
||||
LookupIterator it(to, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
||||
if (it.IsFound() && it.HasProperty()) continue;
|
||||
if (it.IsFound()) continue;
|
||||
// Set the property.
|
||||
Handle<Object> value = Handle<Object>(properties->ValueAt(i),
|
||||
isolate());
|
||||
|
@ -5297,21 +5297,17 @@ HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it,
|
||||
}
|
||||
|
||||
switch (it->state()) {
|
||||
case LookupIterator::ACCESSOR:
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
return kUseGeneric;
|
||||
case LookupIterator::PROPERTY:
|
||||
if (!it->HasProperty()) return kUseGeneric;
|
||||
switch (it->property_kind()) {
|
||||
case LookupIterator::DATA:
|
||||
if (access_type == STORE && it->IsReadOnly()) return kUseGeneric;
|
||||
return kUseCell;
|
||||
case LookupIterator::ACCESSOR:
|
||||
return kUseGeneric;
|
||||
}
|
||||
case LookupIterator::DATA:
|
||||
if (access_type == STORE && it->IsReadOnly()) return kUseGeneric;
|
||||
return kUseCell;
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
@ -709,8 +709,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
|
||||
!holder().is_identical_to(it->GetHolder<JSObject>());
|
||||
bool must_preserve_receiver_reg =
|
||||
!receiver().is(holder_reg) &&
|
||||
(it->property_kind() == LookupIterator::ACCESSOR ||
|
||||
must_perform_prototype_check);
|
||||
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
|
||||
|
||||
// Save necessary data before invoking an interceptor.
|
||||
// Requires a frame to make GC aware of pushed pointers.
|
||||
|
@ -760,8 +760,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
|
||||
!holder().is_identical_to(it->GetHolder<JSObject>());
|
||||
bool must_preserve_receiver_reg =
|
||||
!receiver().is(holder_reg) &&
|
||||
(it->property_kind() == LookupIterator::ACCESSOR ||
|
||||
must_perform_prototype_check);
|
||||
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
|
||||
|
||||
// Save necessary data before invoking an interceptor.
|
||||
// Requires a frame to make GC aware of pushed pointers.
|
||||
|
@ -225,22 +225,28 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
|
||||
// So far the most popular follow ups for interceptor loads are FIELD and
|
||||
// ExecutableAccessorInfo, so inline only them. Other cases may be added
|
||||
// later.
|
||||
bool inline_followup = it->state() == LookupIterator::PROPERTY;
|
||||
if (inline_followup) {
|
||||
switch (it->property_kind()) {
|
||||
case LookupIterator::DATA:
|
||||
inline_followup = it->property_details().type() == FIELD;
|
||||
break;
|
||||
case LookupIterator::ACCESSOR: {
|
||||
Handle<Object> accessors = it->GetAccessors();
|
||||
inline_followup = accessors->IsExecutableAccessorInfo();
|
||||
if (!inline_followup) break;
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(accessors);
|
||||
inline_followup = info->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(
|
||||
isolate(), info, type());
|
||||
}
|
||||
bool inline_followup = false;
|
||||
switch (it->state()) {
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
break;
|
||||
case LookupIterator::DATA:
|
||||
inline_followup = it->property_details().type() == FIELD;
|
||||
break;
|
||||
case LookupIterator::ACCESSOR: {
|
||||
Handle<Object> accessors = it->GetAccessors();
|
||||
inline_followup = accessors->IsExecutableAccessorInfo();
|
||||
if (!inline_followup) break;
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(accessors);
|
||||
inline_followup = info->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(
|
||||
isolate(), info, type());
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,7 +270,14 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
|
||||
set_holder(real_named_property_holder);
|
||||
Register reg = Frontend(interceptor_reg, it->name());
|
||||
|
||||
switch (it->property_kind()) {
|
||||
switch (it->state()) {
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::DATA: {
|
||||
DCHECK_EQ(FIELD, it->property_details().type());
|
||||
__ Move(receiver(), reg);
|
||||
|
@ -699,8 +699,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
|
||||
!holder().is_identical_to(it->GetHolder<JSObject>());
|
||||
bool must_preserve_receiver_reg =
|
||||
!receiver().is(holder_reg) &&
|
||||
(it->property_kind() == LookupIterator::ACCESSOR ||
|
||||
must_perform_prototype_check);
|
||||
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
|
||||
|
||||
// Save necessary data before invoking an interceptor.
|
||||
// Requires a frame to make GC aware of pushed pointers.
|
||||
|
32
src/ic/ic.cc
32
src/ic/ic.cc
@ -215,6 +215,7 @@ static void LookupForRead(LookupIterator* it) {
|
||||
switch (it->state()) {
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::JSPROXY:
|
||||
return;
|
||||
@ -234,9 +235,9 @@ static void LookupForRead(LookupIterator* it) {
|
||||
break;
|
||||
}
|
||||
return;
|
||||
case LookupIterator::PROPERTY:
|
||||
if (it->HasProperty()) return; // Yay!
|
||||
break;
|
||||
case LookupIterator::ACCESSOR:
|
||||
case LookupIterator::DATA:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,7 +286,7 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
|
||||
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
|
||||
LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
if (it.state() == LookupIterator::ACCESS_CHECK) return false;
|
||||
if (!it.IsFound() || !it.HasProperty()) return false;
|
||||
if (!it.IsFound()) return false;
|
||||
Handle<PropertyCell> cell = it.GetPropertyCell();
|
||||
return cell->type()->IsConstant();
|
||||
}
|
||||
@ -976,8 +977,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
}
|
||||
|
||||
// -------------- Accessors --------------
|
||||
DCHECK(lookup->state() == LookupIterator::PROPERTY);
|
||||
if (lookup->property_kind() == LookupIterator::ACCESSOR) {
|
||||
if (lookup->state() == LookupIterator::ACCESSOR) {
|
||||
// Use simple field loads for some well-known callback properties.
|
||||
if (receiver_is_holder) {
|
||||
DCHECK(receiver->IsJSObject());
|
||||
@ -1032,7 +1032,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
}
|
||||
|
||||
// -------------- Dictionary properties --------------
|
||||
DCHECK(lookup->property_kind() == LookupIterator::DATA);
|
||||
DCHECK(lookup->state() == LookupIterator::DATA);
|
||||
if (lookup->property_encoding() == LookupIterator::DICTIONARY) {
|
||||
if (kind() != Code::LOAD_IC) return slow_stub();
|
||||
if (holder->IsGlobalObject()) {
|
||||
@ -1223,6 +1223,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
switch (it->state()) {
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::JSPROXY:
|
||||
return false;
|
||||
@ -1240,11 +1241,12 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
|
||||
break;
|
||||
case LookupIterator::PROPERTY:
|
||||
if (!it->HasProperty()) break;
|
||||
case LookupIterator::ACCESSOR:
|
||||
return !it->IsReadOnly();
|
||||
case LookupIterator::DATA: {
|
||||
if (it->IsReadOnly()) return false;
|
||||
if (it->property_kind() == LookupIterator::ACCESSOR) return true;
|
||||
if (it->GetHolder<Object>().is_identical_to(receiver)) {
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
if (receiver.is_identical_to(holder)) {
|
||||
it->PrepareForDataProperty(value);
|
||||
// The previous receiver map might just have been deprecated,
|
||||
// so reload it.
|
||||
@ -1253,14 +1255,15 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
}
|
||||
|
||||
// Receiver != holder.
|
||||
PrototypeIterator iter(it->isolate(), receiver);
|
||||
if (receiver->IsJSGlobalProxy()) {
|
||||
PrototypeIterator iter(it->isolate(), receiver);
|
||||
return it->GetHolder<Object>().is_identical_to(
|
||||
PrototypeIterator::GetCurrent(iter));
|
||||
}
|
||||
|
||||
it->PrepareTransitionToDataProperty(value, NONE, store_mode);
|
||||
return it->IsCacheableTransition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1417,8 +1420,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
}
|
||||
|
||||
// -------------- Accessors --------------
|
||||
DCHECK(lookup->state() == LookupIterator::PROPERTY);
|
||||
if (lookup->property_kind() == LookupIterator::ACCESSOR) {
|
||||
if (lookup->state() == LookupIterator::ACCESSOR) {
|
||||
if (!holder->HasFastProperties()) return slow_stub();
|
||||
Handle<Object> accessors = lookup->GetAccessors();
|
||||
if (accessors->IsExecutableAccessorInfo()) {
|
||||
@ -1452,7 +1454,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
}
|
||||
|
||||
// -------------- Dictionary properties --------------
|
||||
DCHECK(lookup->property_kind() == LookupIterator::DATA);
|
||||
DCHECK(lookup->state() == LookupIterator::DATA);
|
||||
if (lookup->property_encoding() == LookupIterator::DICTIONARY) {
|
||||
if (holder->IsGlobalObject()) {
|
||||
Handle<PropertyCell> cell = lookup->GetPropertyCell();
|
||||
|
@ -710,8 +710,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
|
||||
!holder().is_identical_to(it->GetHolder<JSObject>());
|
||||
bool must_preserve_receiver_reg =
|
||||
!receiver().is(holder_reg) &&
|
||||
(it->property_kind() == LookupIterator::ACCESSOR ||
|
||||
must_perform_prototype_check);
|
||||
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
|
||||
|
||||
// Save necessary data before invoking an interceptor.
|
||||
// Requires a frame to make GC aware of pushed pointers.
|
||||
|
@ -710,8 +710,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
|
||||
!holder().is_identical_to(it->GetHolder<JSObject>());
|
||||
bool must_preserve_receiver_reg =
|
||||
!receiver().is(holder_reg) &&
|
||||
(it->property_kind() == LookupIterator::ACCESSOR ||
|
||||
must_perform_prototype_check);
|
||||
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
|
||||
|
||||
// Save necessary data before invoking an interceptor.
|
||||
// Requires a frame to make GC aware of pushed pointers.
|
||||
|
@ -694,8 +694,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
|
||||
!holder().is_identical_to(it->GetHolder<JSObject>());
|
||||
bool must_preserve_receiver_reg =
|
||||
!receiver().is(holder_reg) &&
|
||||
(it->property_kind() == LookupIterator::ACCESSOR ||
|
||||
must_perform_prototype_check);
|
||||
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
|
||||
|
||||
// Save necessary data before invoking an interceptor.
|
||||
// Requires a frame to make GC aware of pushed pointers.
|
||||
|
@ -747,8 +747,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
|
||||
!holder().is_identical_to(it->GetHolder<JSObject>());
|
||||
bool must_preserve_receiver_reg =
|
||||
!receiver().is(holder_reg) &&
|
||||
(it->property_kind() == LookupIterator::ACCESSOR ||
|
||||
must_perform_prototype_check);
|
||||
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
|
||||
|
||||
// Save necessary data before invoking an interceptor.
|
||||
// Requires a frame to make GC aware of pushed pointers.
|
||||
|
@ -31,7 +31,8 @@ JSReceiver* LookupIterator::NextHolder(Map* map) {
|
||||
}
|
||||
|
||||
|
||||
LookupIterator::State LookupIterator::LookupInHolder(Map* map) {
|
||||
LookupIterator::State LookupIterator::LookupInHolder(Map* map,
|
||||
JSReceiver* holder) {
|
||||
STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
|
||||
DisallowHeapAllocation no_gc;
|
||||
switch (state_) {
|
||||
@ -47,14 +48,35 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map) {
|
||||
case INTERCEPTOR:
|
||||
if (map->is_dictionary_map()) {
|
||||
property_encoding_ = DICTIONARY;
|
||||
if (holder == NULL) return UNKNOWN;
|
||||
NameDictionary* dict = JSObject::cast(holder)->property_dictionary();
|
||||
number_ = dict->FindEntry(name_);
|
||||
if (number_ == NameDictionary::kNotFound) return NOT_FOUND;
|
||||
property_details_ = dict->DetailsAt(number_);
|
||||
if (holder->IsGlobalObject()) {
|
||||
if (property_details_.IsDeleted()) return NOT_FOUND;
|
||||
PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
|
||||
if (cell->value()->IsTheHole()) return NOT_FOUND;
|
||||
}
|
||||
} else {
|
||||
DescriptorArray* descriptors = map->instance_descriptors();
|
||||
number_ = descriptors->SearchWithCache(*name_, map);
|
||||
if (number_ == DescriptorArray::kNotFound) return NOT_FOUND;
|
||||
property_encoding_ = DESCRIPTOR;
|
||||
property_details_ = descriptors->GetDetails(number_);
|
||||
}
|
||||
return PROPERTY;
|
||||
case PROPERTY:
|
||||
has_property_ = true;
|
||||
switch (property_details_.type()) {
|
||||
case v8::internal::CONSTANT:
|
||||
case v8::internal::FIELD:
|
||||
case v8::internal::NORMAL:
|
||||
return DATA;
|
||||
case v8::internal::CALLBACKS:
|
||||
return ACCESSOR;
|
||||
}
|
||||
case ACCESSOR:
|
||||
case DATA:
|
||||
case UNKNOWN:
|
||||
return NOT_FOUND;
|
||||
case JSPROXY:
|
||||
case TRANSITION:
|
||||
|
@ -14,25 +14,28 @@ namespace internal {
|
||||
|
||||
|
||||
void LookupIterator::Next() {
|
||||
DCHECK_NE(JSPROXY, state_);
|
||||
DCHECK_NE(TRANSITION, state_);
|
||||
DisallowHeapAllocation no_gc;
|
||||
has_property_ = false;
|
||||
|
||||
JSReceiver* holder = NULL;
|
||||
JSReceiver* holder =
|
||||
maybe_holder_.is_null() ? NULL : *maybe_holder_.ToHandleChecked();
|
||||
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, isolate_);
|
||||
@ -81,58 +84,15 @@ bool LookupIterator::HasAccess(v8::AccessType access_type) const {
|
||||
}
|
||||
|
||||
|
||||
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_);
|
||||
}
|
||||
|
||||
LoadPropertyKind();
|
||||
|
||||
has_property_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LookupIterator::LoadPropertyKind() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LookupIterator::ReloadPropertyInformation() {
|
||||
state_ = BEFORE_PROPERTY;
|
||||
state_ = LookupInHolder(*holder_map_);
|
||||
DCHECK(IsFound());
|
||||
HasProperty();
|
||||
state_ = LookupInHolder(*holder_map_, *maybe_holder_.ToHandleChecked());
|
||||
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;
|
||||
holder_map_ =
|
||||
@ -144,7 +104,7 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
|
||||
|
||||
void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
|
||||
PropertyAttributes attributes) {
|
||||
DCHECK(has_property_);
|
||||
DCHECK(state_ == DATA || state_ == ACCESSOR);
|
||||
DCHECK(HolderIsReceiverOrHiddenPrototype());
|
||||
Handle<JSObject> holder = GetHolder<JSObject>();
|
||||
if (property_encoding_ != DICTIONARY) {
|
||||
@ -166,9 +126,9 @@ void LookupIterator::PrepareTransitionToDataProperty(
|
||||
Handle<Object> value, PropertyAttributes attributes,
|
||||
Object::StoreFromKeyed store_mode) {
|
||||
if (state_ == TRANSITION) return;
|
||||
DCHECK(!has_property_ || property_kind_ != ACCESSOR);
|
||||
DCHECK(!(has_property_ || state_ == JSPROXY) ||
|
||||
!HolderIsReceiverOrHiddenPrototype());
|
||||
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
|
||||
@ -224,8 +184,7 @@ void LookupIterator::TransitionToAccessorProperty(
|
||||
// Install the accessor into the dictionary-mode object.
|
||||
PropertyDetails details(attributes, CALLBACKS, 0);
|
||||
Handle<AccessorPair> pair;
|
||||
if (IsFound() && HasProperty() && property_kind() == ACCESSOR &&
|
||||
GetAccessors()->IsAccessorPair()) {
|
||||
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) {
|
||||
@ -331,15 +290,13 @@ 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;
|
||||
}
|
||||
@ -347,7 +304,7 @@ Handle<Object> LookupIterator::GetDataValue() const {
|
||||
|
||||
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) {
|
||||
NameDictionary* property_dictionary = holder->property_dictionary();
|
||||
|
24
src/lookup.h
24
src/lookup.h
@ -34,18 +34,15 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
INTERCEPTOR,
|
||||
JSPROXY,
|
||||
NOT_FOUND,
|
||||
PROPERTY,
|
||||
UNKNOWN, // Dictionary-mode holder map without a holder.
|
||||
ACCESSOR,
|
||||
DATA,
|
||||
TRANSITION,
|
||||
// Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
|
||||
// PROPERTY lookup.
|
||||
BEFORE_PROPERTY = INTERCEPTOR
|
||||
};
|
||||
|
||||
enum PropertyKind {
|
||||
DATA,
|
||||
ACCESSOR
|
||||
};
|
||||
|
||||
enum PropertyEncoding {
|
||||
DICTIONARY,
|
||||
DESCRIPTOR
|
||||
@ -55,7 +52,6 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
Configuration configuration = PROTOTYPE_CHAIN)
|
||||
: configuration_(ComputeConfiguration(configuration, name)),
|
||||
state_(NOT_FOUND),
|
||||
property_kind_(DATA),
|
||||
property_encoding_(DESCRIPTOR),
|
||||
property_details_(NONE, NORMAL, Representation::None()),
|
||||
isolate_(name->GetIsolate()),
|
||||
@ -73,7 +69,6 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
Configuration configuration = PROTOTYPE_CHAIN)
|
||||
: configuration_(ComputeConfiguration(configuration, name)),
|
||||
state_(NOT_FOUND),
|
||||
property_kind_(DATA),
|
||||
property_encoding_(DESCRIPTOR),
|
||||
property_details_(NONE, NORMAL, Representation::None()),
|
||||
isolate_(name->GetIsolate()),
|
||||
@ -118,10 +113,6 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
bool HasAccess(v8::AccessType access_type) const;
|
||||
|
||||
/* PROPERTY */
|
||||
// HasProperty needs to be called before any of the other PROPERTY methods
|
||||
// below can be used. It ensures that we are able to provide a definite
|
||||
// answer, and loads extra information about the property.
|
||||
bool HasProperty();
|
||||
void PrepareForDataProperty(Handle<Object> value);
|
||||
void PrepareTransitionToDataProperty(Handle<Object> value,
|
||||
PropertyAttributes attributes,
|
||||
@ -131,7 +122,6 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
state_ == TRANSITION && transition_map()->GetBackPointer()->IsMap();
|
||||
if (cacheable) {
|
||||
property_details_ = transition_map_->GetLastDescriptorDetails();
|
||||
LoadPropertyKind();
|
||||
has_property_ = true;
|
||||
}
|
||||
return cacheable;
|
||||
@ -142,10 +132,6 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
void TransitionToAccessorProperty(AccessorComponent component,
|
||||
Handle<Object> accessor,
|
||||
PropertyAttributes attributes);
|
||||
PropertyKind property_kind() const {
|
||||
DCHECK(has_property_);
|
||||
return property_kind_;
|
||||
}
|
||||
PropertyEncoding property_encoding() const {
|
||||
DCHECK(has_property_);
|
||||
return property_encoding_;
|
||||
@ -173,10 +159,9 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
Handle<Map> GetReceiverMap() const;
|
||||
|
||||
MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
|
||||
inline State LookupInHolder(Map* map);
|
||||
inline State LookupInHolder(Map* map, JSReceiver* holder);
|
||||
Handle<Object> FetchValue() const;
|
||||
void ReloadPropertyInformation();
|
||||
void LoadPropertyKind();
|
||||
|
||||
bool IsBootstrapping() const;
|
||||
|
||||
@ -219,7 +204,6 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
Configuration configuration_;
|
||||
State state_;
|
||||
bool has_property_;
|
||||
PropertyKind property_kind_;
|
||||
PropertyEncoding property_encoding_;
|
||||
PropertyDetails property_details_;
|
||||
Isolate* isolate_;
|
||||
|
288
src/objects.cc
288
src/objects.cc
@ -110,6 +110,7 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
|
||||
switch (it->state()) {
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::JSPROXY:
|
||||
return JSProxy::GetPropertyWithHandler(it->GetHolder<JSProxy>(),
|
||||
@ -124,18 +125,12 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
if (it->HasAccess(v8::ACCESS_GET)) break;
|
||||
return JSObject::GetPropertyWithFailedAccessCheck(it);
|
||||
case LookupIterator::PROPERTY:
|
||||
if (it->HasProperty()) {
|
||||
switch (it->property_kind()) {
|
||||
case LookupIterator::ACCESSOR:
|
||||
return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
|
||||
it->GetHolder<JSObject>(),
|
||||
it->GetAccessors());
|
||||
case LookupIterator::DATA:
|
||||
return it->GetDataValue();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LookupIterator::ACCESSOR:
|
||||
return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
|
||||
it->GetHolder<JSObject>(),
|
||||
it->GetAccessors());
|
||||
case LookupIterator::DATA:
|
||||
return it->GetDataValue();
|
||||
}
|
||||
}
|
||||
return it->factory()->undefined_value();
|
||||
@ -156,6 +151,7 @@ Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
if (it->HasAccess(v8::ACCESS_GET)) continue;
|
||||
@ -163,18 +159,14 @@ Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
|
||||
case LookupIterator::JSPROXY:
|
||||
it->NotFound();
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
case LookupIterator::PROPERTY:
|
||||
if (!it->HasProperty()) continue;
|
||||
switch (it->property_kind()) {
|
||||
case LookupIterator::DATA:
|
||||
return it->GetDataValue();
|
||||
case LookupIterator::ACCESSOR:
|
||||
// TODO(verwaest): For now this doesn't call into
|
||||
// ExecutableAccessorInfo, since clients don't need it. Update once
|
||||
// relevant.
|
||||
it->NotFound();
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
}
|
||||
case LookupIterator::ACCESSOR:
|
||||
// TODO(verwaest): For now this doesn't call into
|
||||
// ExecutableAccessorInfo, since clients don't need it. Update once
|
||||
// relevant.
|
||||
it->NotFound();
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
case LookupIterator::DATA:
|
||||
return it->GetDataValue();
|
||||
}
|
||||
}
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
@ -582,9 +574,7 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
|
||||
|
||||
static bool FindAllCanReadHolder(LookupIterator* it) {
|
||||
for (; it->IsFound(); it->Next()) {
|
||||
if (it->state() == LookupIterator::PROPERTY &&
|
||||
it->HasProperty() &&
|
||||
it->property_kind() == LookupIterator::ACCESSOR) {
|
||||
if (it->state() == LookupIterator::ACCESSOR) {
|
||||
Handle<Object> accessors = it->GetAccessors();
|
||||
if (accessors->IsAccessorInfo()) {
|
||||
if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
|
||||
@ -623,8 +613,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
|
||||
|
||||
static bool FindAllCanWriteHolder(LookupIterator* it) {
|
||||
for (; it->IsFound(); it->Next()) {
|
||||
if (it->state() == LookupIterator::PROPERTY && it->HasProperty() &&
|
||||
it->property_kind() == LookupIterator::ACCESSOR) {
|
||||
if (it->state() == LookupIterator::ACCESSOR) {
|
||||
Handle<Object> accessors = it->GetAccessors();
|
||||
if (accessors->IsAccessorInfo()) {
|
||||
if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
|
||||
@ -2830,6 +2819,7 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
|
||||
for (; it->IsFound(); it->Next()) {
|
||||
switch (it->state()) {
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
@ -2875,24 +2865,25 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
|
||||
}
|
||||
break;
|
||||
|
||||
case LookupIterator::PROPERTY:
|
||||
if (!it->HasProperty()) break;
|
||||
case LookupIterator::ACCESSOR:
|
||||
if (it->property_details().IsReadOnly()) {
|
||||
return WriteToReadOnlyProperty(it, value, strict_mode);
|
||||
}
|
||||
switch (it->property_kind()) {
|
||||
case LookupIterator::ACCESSOR:
|
||||
if (it->HolderIsReceiverOrHiddenPrototype() ||
|
||||
!it->GetAccessors()->IsDeclaredAccessorInfo()) {
|
||||
return SetPropertyWithAccessor(it->GetReceiver(), it->name(),
|
||||
value, it->GetHolder<JSObject>(),
|
||||
it->GetAccessors(), strict_mode);
|
||||
}
|
||||
break;
|
||||
case LookupIterator::DATA:
|
||||
if (it->HolderIsReceiverOrHiddenPrototype()) {
|
||||
return SetDataProperty(it, value);
|
||||
}
|
||||
if (it->HolderIsReceiverOrHiddenPrototype() ||
|
||||
!it->GetAccessors()->IsDeclaredAccessorInfo()) {
|
||||
return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
|
||||
it->GetHolder<JSObject>(),
|
||||
it->GetAccessors(), strict_mode);
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case LookupIterator::DATA:
|
||||
if (it->property_details().IsReadOnly()) {
|
||||
return WriteToReadOnlyProperty(it, value, strict_mode);
|
||||
}
|
||||
if (it->HolderIsReceiverOrHiddenPrototype()) {
|
||||
return SetDataProperty(it, value);
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
@ -3825,6 +3816,7 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
@ -3833,86 +3825,67 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
}
|
||||
break;
|
||||
|
||||
case LookupIterator::PROPERTY: {
|
||||
if (!it.HasProperty()) break;
|
||||
case LookupIterator::ACCESSOR: {
|
||||
PropertyDetails details = it.property_details();
|
||||
Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
|
||||
switch (it.property_kind()) {
|
||||
case LookupIterator::ACCESSOR: {
|
||||
// Ensure the context isn't changed after calling into accessors.
|
||||
AssertNoContextChange ncc(it.isolate());
|
||||
// Ensure the context isn't changed after calling into accessors.
|
||||
AssertNoContextChange ncc(it.isolate());
|
||||
|
||||
Handle<Object> accessors = it.GetAccessors();
|
||||
Handle<Object> accessors = it.GetAccessors();
|
||||
|
||||
if (is_observed && accessors->IsAccessorInfo()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
it.isolate(), old_value,
|
||||
GetPropertyWithAccessor(it.GetReceiver(), it.name(),
|
||||
it.GetHolder<JSObject>(), accessors),
|
||||
Object);
|
||||
}
|
||||
if (is_observed && accessors->IsAccessorInfo()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
it.isolate(), old_value,
|
||||
GetPropertyWithAccessor(it.GetReceiver(), it.name(),
|
||||
it.GetHolder<JSObject>(), accessors),
|
||||
Object);
|
||||
}
|
||||
|
||||
// Special handling for ExecutableAccessorInfo, which behaves like a
|
||||
// data property.
|
||||
if (handling == DONT_FORCE_FIELD &&
|
||||
accessors->IsExecutableAccessorInfo()) {
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
it.isolate(), result,
|
||||
JSObject::SetPropertyWithAccessor(
|
||||
it.GetReceiver(), it.name(), value,
|
||||
it.GetHolder<JSObject>(), accessors, STRICT),
|
||||
Object);
|
||||
DCHECK(result->SameValue(*value));
|
||||
// Special handling for ExecutableAccessorInfo, which behaves like a
|
||||
// data property.
|
||||
if (handling == DONT_FORCE_FIELD &&
|
||||
accessors->IsExecutableAccessorInfo()) {
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
it.isolate(), result,
|
||||
JSObject::SetPropertyWithAccessor(it.GetReceiver(), it.name(),
|
||||
value, it.GetHolder<JSObject>(),
|
||||
accessors, STRICT),
|
||||
Object);
|
||||
DCHECK(result->SameValue(*value));
|
||||
|
||||
if (details.attributes() == attributes) {
|
||||
// Regular property update if the attributes match.
|
||||
if (is_observed && !old_value->SameValue(*value)) {
|
||||
// If we are setting the prototype of a function and are
|
||||
// observed, don't send change records because the prototype
|
||||
// handles that itself.
|
||||
if (!object->IsJSFunction() ||
|
||||
!Name::Equals(it.isolate()->factory()->prototype_string(),
|
||||
name) ||
|
||||
!Handle<JSFunction>::cast(object)
|
||||
->should_have_prototype()) {
|
||||
EnqueueChangeRecord(object, "update", name, old_value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
if (details.attributes() == attributes) {
|
||||
// Regular property update if the attributes match.
|
||||
if (is_observed && !old_value->SameValue(*value)) {
|
||||
// If we are setting the prototype of a function and are
|
||||
// observed, don't send change records because the prototype
|
||||
// handles that itself.
|
||||
if (!object->IsJSFunction() ||
|
||||
!Name::Equals(it.isolate()->factory()->prototype_string(),
|
||||
name) ||
|
||||
!Handle<JSFunction>::cast(object)->should_have_prototype()) {
|
||||
EnqueueChangeRecord(object, "update", name, old_value);
|
||||
}
|
||||
|
||||
// Reconfigure the accessor if attributes mismatch.
|
||||
Handle<ExecutableAccessorInfo> new_data =
|
||||
Accessors::CloneAccessor(
|
||||
it.isolate(),
|
||||
Handle<ExecutableAccessorInfo>::cast(accessors));
|
||||
new_data->set_property_attributes(attributes);
|
||||
// By clearing the setter we don't have to introduce a lookup to
|
||||
// the setter, simply make it unavailable to reflect the
|
||||
// attributes.
|
||||
if (attributes & READ_ONLY) new_data->clear_setter();
|
||||
SetPropertyCallback(object, name, new_data, attributes);
|
||||
if (is_observed) {
|
||||
if (old_value->SameValue(*value)) {
|
||||
old_value = it.isolate()->factory()->the_hole_value();
|
||||
}
|
||||
EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Regular accessor. Reconfigure to data property.
|
||||
break;
|
||||
return value;
|
||||
}
|
||||
|
||||
case LookupIterator::DATA:
|
||||
// Regular property update if the attributes match.
|
||||
if (details.attributes() == attributes) {
|
||||
return SetDataProperty(&it, value);
|
||||
// Reconfigure the accessor if attributes mismatch.
|
||||
Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor(
|
||||
it.isolate(), Handle<ExecutableAccessorInfo>::cast(accessors));
|
||||
new_data->set_property_attributes(attributes);
|
||||
// By clearing the setter we don't have to introduce a lookup to
|
||||
// the setter, simply make it unavailable to reflect the
|
||||
// attributes.
|
||||
if (attributes & READ_ONLY) new_data->clear_setter();
|
||||
SetPropertyCallback(object, name, new_data, attributes);
|
||||
if (is_observed) {
|
||||
if (old_value->SameValue(*value)) {
|
||||
old_value = it.isolate()->factory()->the_hole_value();
|
||||
}
|
||||
// Reconfigure the data property if the attributes mismatch.
|
||||
if (is_observed) old_value = it.GetDataValue();
|
||||
EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
it.ReconfigureDataProperty(value, attributes);
|
||||
@ -3928,6 +3901,30 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
case LookupIterator::DATA: {
|
||||
PropertyDetails details = it.property_details();
|
||||
Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
|
||||
// Regular property update if the attributes match.
|
||||
if (details.attributes() == attributes) {
|
||||
return SetDataProperty(&it, value);
|
||||
}
|
||||
// Reconfigure the data property if the attributes mismatch.
|
||||
if (is_observed) old_value = it.GetDataValue();
|
||||
|
||||
it.ReconfigureDataProperty(value, attributes);
|
||||
it.PrepareForDataProperty(value);
|
||||
it.WriteDataValue(value);
|
||||
|
||||
if (is_observed) {
|
||||
if (old_value->SameValue(*value)) {
|
||||
old_value = it.isolate()->factory()->the_hole_value();
|
||||
}
|
||||
EnqueueChangeRecord(object, "reconfigure", name, old_value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3996,6 +3993,7 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
|
||||
for (; it->IsFound(); it->Next()) {
|
||||
switch (it->state()) {
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::UNKNOWN:
|
||||
case LookupIterator::TRANSITION:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::JSPROXY:
|
||||
@ -4012,11 +4010,9 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
if (it->HasAccess(v8::ACCESS_HAS)) break;
|
||||
return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
|
||||
case LookupIterator::PROPERTY:
|
||||
if (it->HasProperty()) {
|
||||
return maybe(it->property_details().attributes());
|
||||
}
|
||||
break;
|
||||
case LookupIterator::ACCESSOR:
|
||||
case LookupIterator::DATA:
|
||||
return maybe(it->property_details().attributes());
|
||||
}
|
||||
}
|
||||
return maybe(ABSENT);
|
||||
@ -4693,7 +4689,7 @@ bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
|
||||
Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string();
|
||||
LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
||||
return it.IsFound() && it.HasProperty();
|
||||
return it.IsFound();
|
||||
}
|
||||
|
||||
|
||||
@ -4726,10 +4722,10 @@ Object* JSObject::GetHiddenPropertiesHashTable() {
|
||||
LookupIterator it(handle(this), isolate->factory()->hidden_string(),
|
||||
LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
||||
if (it.IsFound() && it.HasProperty()) {
|
||||
DCHECK_EQ(LookupIterator::DATA, it.property_kind());
|
||||
if (it.state() == LookupIterator::DATA) {
|
||||
return *it.GetDataValue();
|
||||
}
|
||||
DCHECK(!it.IsFound());
|
||||
return GetHeap()->undefined_value();
|
||||
}
|
||||
}
|
||||
@ -4926,12 +4922,14 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
|
||||
bool is_observed = object->map()->is_observed() &&
|
||||
*name != it.isolate()->heap()->hidden_string();
|
||||
Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
|
||||
|
||||
for (; it.IsFound(); it.Next()) {
|
||||
switch (it.state()) {
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
if (it.HasAccess(v8::ACCESS_DELETE)) break;
|
||||
@ -4949,8 +4947,12 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
if (it.isolate()->has_pending_exception()) return maybe_result;
|
||||
break;
|
||||
}
|
||||
case LookupIterator::PROPERTY: {
|
||||
if (!it.HasProperty()) continue;
|
||||
case LookupIterator::DATA:
|
||||
if (is_observed) {
|
||||
old_value = it.GetDataValue();
|
||||
}
|
||||
// Fall through.
|
||||
case LookupIterator::ACCESSOR: {
|
||||
if (delete_mode != FORCE_DELETION && !it.IsConfigurable()) {
|
||||
// Fail if the property is not configurable.
|
||||
if (delete_mode == STRICT_DELETION) {
|
||||
@ -4963,17 +4965,6 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
return it.isolate()->factory()->false_value();
|
||||
}
|
||||
|
||||
Handle<Object> old_value;
|
||||
if (is_observed) {
|
||||
switch (it.property_kind()) {
|
||||
case LookupIterator::ACCESSOR:
|
||||
old_value = it.isolate()->factory()->the_hole_value();
|
||||
break;
|
||||
case LookupIterator::DATA:
|
||||
old_value = it.GetDataValue();
|
||||
}
|
||||
}
|
||||
|
||||
PropertyNormalizationMode mode = object->map()->is_prototype_map()
|
||||
? KEEP_INOBJECT_PROPERTIES
|
||||
: CLEAR_INOBJECT_PROPERTIES;
|
||||
@ -6150,7 +6141,7 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
|
||||
LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
||||
CHECK(GetPropertyAttributes(&it).has_value);
|
||||
preexists = it.IsFound();
|
||||
if (preexists && (it.property_kind() == LookupIterator::DATA ||
|
||||
if (preexists && (it.state() == LookupIterator::DATA ||
|
||||
it.GetAccessors()->IsAccessorInfo())) {
|
||||
old_value = GetProperty(&it).ToHandleChecked();
|
||||
}
|
||||
@ -6314,6 +6305,7 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
@ -6326,20 +6318,16 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
|
||||
case LookupIterator::JSPROXY:
|
||||
return isolate->factory()->undefined_value();
|
||||
|
||||
case LookupIterator::PROPERTY:
|
||||
if (!it.HasProperty()) continue;
|
||||
switch (it.property_kind()) {
|
||||
case LookupIterator::DATA:
|
||||
continue;
|
||||
case LookupIterator::ACCESSOR: {
|
||||
Handle<Object> maybe_pair = it.GetAccessors();
|
||||
if (maybe_pair->IsAccessorPair()) {
|
||||
return handle(
|
||||
AccessorPair::cast(*maybe_pair)->GetComponent(component),
|
||||
isolate);
|
||||
}
|
||||
}
|
||||
case LookupIterator::DATA:
|
||||
continue;
|
||||
case LookupIterator::ACCESSOR: {
|
||||
Handle<Object> maybe_pair = it.GetAccessors();
|
||||
if (maybe_pair->IsAccessorPair()) {
|
||||
return handle(
|
||||
AccessorPair::cast(*maybe_pair)->GetComponent(component),
|
||||
isolate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12849,7 +12837,7 @@ bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
|
||||
LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
||||
CHECK(it.IsFound());
|
||||
CHECK(it.HasProperty());
|
||||
CHECK_EQ(LookupIterator::ACCESSOR, it.state());
|
||||
return it.IsReadOnly();
|
||||
}
|
||||
return false;
|
||||
@ -13275,7 +13263,7 @@ Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
|
||||
LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
|
||||
if (!maybe_result.has_value) return Maybe<bool>();
|
||||
return maybe(it.IsFound() && it.property_kind() == LookupIterator::ACCESSOR);
|
||||
return maybe(it.state() == LookupIterator::ACCESSOR);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1990,8 +1990,7 @@ MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
|
||||
if (attrs == ABSENT) return factory->undefined_value();
|
||||
|
||||
// Get AccessorPair if present.
|
||||
if (it.state() == LookupIterator::PROPERTY &&
|
||||
it.property_kind() == LookupIterator::ACCESSOR &&
|
||||
if (it.state() == LookupIterator::ACCESSOR &&
|
||||
it.GetAccessors()->IsAccessorPair()) {
|
||||
maybe_accessors = Handle<AccessorPair>::cast(it.GetAccessors());
|
||||
}
|
||||
@ -2323,7 +2322,7 @@ RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
|
||||
// Ignore if we can't reconfigure the value.
|
||||
if ((old_attributes & DONT_DELETE) != 0) {
|
||||
if ((old_attributes & READ_ONLY) != 0 ||
|
||||
it.property_kind() == LookupIterator::ACCESSOR) {
|
||||
it.state() == LookupIterator::ACCESSOR) {
|
||||
return *value;
|
||||
}
|
||||
attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
|
||||
@ -2468,7 +2467,7 @@ RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
|
||||
// Ignore if we can't reconfigure the value.
|
||||
if ((old_attributes & DONT_DELETE) != 0) {
|
||||
if ((old_attributes & READ_ONLY) != 0 ||
|
||||
it.property_kind() == LookupIterator::ACCESSOR) {
|
||||
it.state() == LookupIterator::ACCESSOR) {
|
||||
return *value;
|
||||
}
|
||||
attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
|
||||
@ -4891,8 +4890,8 @@ RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
|
||||
// Lookup cache miss. Perform lookup and update the cache if
|
||||
// appropriate.
|
||||
LookupIterator it(receiver, key, LookupIterator::OWN);
|
||||
if (it.IsFound() && it.state() == LookupIterator::PROPERTY &&
|
||||
it.HasProperty() && it.property_details().type() == FIELD) {
|
||||
if (it.state() == LookupIterator::DATA &&
|
||||
it.property_details().type() == FIELD) {
|
||||
FieldIndex field_index = it.GetFieldIndex();
|
||||
// Do not track double fields in the keyed lookup cache. Reading
|
||||
// double values requires boxing.
|
||||
@ -5050,8 +5049,7 @@ RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) {
|
||||
|
||||
// Take special care when attributes are different and there is already
|
||||
// a property.
|
||||
if (it.IsFound() && it.HasProperty() &&
|
||||
it.property_kind() == LookupIterator::ACCESSOR) {
|
||||
if (it.state() == LookupIterator::ACCESSOR) {
|
||||
// Use IgnoreAttributes version since a readonly property may be
|
||||
// overridden and SetProperty does not allow this.
|
||||
Handle<Object> result;
|
||||
@ -10898,6 +10896,7 @@ static Handle<Object> DebugGetProperty(LookupIterator* it,
|
||||
switch (it->state()) {
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::TRANSITION:
|
||||
case LookupIterator::UNKNOWN:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
// Ignore access checks.
|
||||
@ -10905,30 +10904,25 @@ static Handle<Object> DebugGetProperty(LookupIterator* it,
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::JSPROXY:
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
case LookupIterator::PROPERTY:
|
||||
if (!it->HasProperty()) continue;
|
||||
switch (it->property_kind()) {
|
||||
case LookupIterator::ACCESSOR: {
|
||||
Handle<Object> accessors = it->GetAccessors();
|
||||
if (!accessors->IsAccessorInfo()) {
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
}
|
||||
MaybeHandle<Object> maybe_result =
|
||||
JSObject::GetPropertyWithAccessor(it->GetReceiver(), it->name(),
|
||||
it->GetHolder<JSObject>(),
|
||||
accessors);
|
||||
Handle<Object> result;
|
||||
if (!maybe_result.ToHandle(&result)) {
|
||||
result =
|
||||
handle(it->isolate()->pending_exception(), it->isolate());
|
||||
it->isolate()->clear_pending_exception();
|
||||
if (has_caught != NULL) *has_caught = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case LookupIterator::DATA:
|
||||
return it->GetDataValue();
|
||||
case LookupIterator::ACCESSOR: {
|
||||
Handle<Object> accessors = it->GetAccessors();
|
||||
if (!accessors->IsAccessorInfo()) {
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
}
|
||||
MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithAccessor(
|
||||
it->GetReceiver(), it->name(), it->GetHolder<JSObject>(),
|
||||
accessors);
|
||||
Handle<Object> result;
|
||||
if (!maybe_result.ToHandle(&result)) {
|
||||
result = handle(it->isolate()->pending_exception(), it->isolate());
|
||||
it->isolate()->clear_pending_exception();
|
||||
if (has_caught != NULL) *has_caught = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
case LookupIterator::DATA:
|
||||
return it->GetDataValue();
|
||||
}
|
||||
}
|
||||
|
||||
@ -10983,8 +10977,7 @@ RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
|
||||
if (!it.IsFound()) return isolate->heap()->undefined_value();
|
||||
|
||||
Handle<Object> maybe_pair;
|
||||
if (it.state() == LookupIterator::PROPERTY &&
|
||||
it.property_kind() == LookupIterator::ACCESSOR) {
|
||||
if (it.state() == LookupIterator::ACCESSOR) {
|
||||
maybe_pair = it.GetAccessors();
|
||||
}
|
||||
|
||||
|
@ -2045,8 +2045,7 @@ THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
|
||||
i::LookupResult lookup(i_isolate);
|
||||
i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
|
||||
i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
CHECK_NE(i::LookupIterator::ACCESS_CHECK, it.state());
|
||||
CHECK(it.HasProperty());
|
||||
CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
|
||||
CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user