Index: src/lookup.cc |
diff --git a/src/lookup.cc b/src/lookup.cc |
index f013efb52908b319e3c9fadd6324641b6eef8a79..1cbff613def4d48aed00f521eb007863fbe8c18a 100644 |
--- a/src/lookup.cc |
+++ b/src/lookup.cc |
@@ -45,26 +45,6 @@ LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate, |
return LookupIterator(receiver, name, configuration); |
} |
-template <bool is_element> |
-void LookupIterator::Start() { |
- DisallowHeapAllocation no_gc; |
- |
- has_property_ = false; |
- state_ = NOT_FOUND; |
- number_ = DescriptorArray::kNotFound; |
- holder_ = initial_holder_; |
- |
- JSReceiver* holder = *holder_; |
- Map* map = holder->map(); |
- |
- state_ = LookupInHolder<is_element>(map, holder); |
- if (IsFound()) return; |
- |
- NextInternal<is_element>(map, holder); |
-} |
- |
-template void LookupIterator::Start<true>(); |
-template void LookupIterator::Start<false>(); |
void LookupIterator::Next() { |
DCHECK_NE(JSPROXY, state_); |
@@ -75,45 +55,38 @@ void LookupIterator::Next() { |
JSReceiver* holder = *holder_; |
Map* map = holder->map(); |
- if (map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { |
- state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder) |
- : LookupInSpecialHolder<false>(map, holder); |
- if (IsFound()) return; |
- } |
- |
- IsElement() ? NextInternal<true>(map, holder) |
- : NextInternal<false>(map, holder); |
-} |
+ // Perform lookup on current holder. |
+ state_ = LookupInHolder(map, holder); |
+ if (IsFound()) return; |
-template <bool is_element> |
-void LookupIterator::NextInternal(Map* map, JSReceiver* holder) { |
+ // Continue lookup if lookup on current holder failed. |
do { |
JSReceiver* maybe_holder = NextHolder(map); |
if (maybe_holder == nullptr) { |
if (interceptor_state_ == InterceptorState::kSkipNonMasking) { |
- RestartLookupForNonMaskingInterceptors<is_element>(); |
+ RestartLookupForNonMaskingInterceptors(); |
return; |
} |
- if (holder != *holder_) holder_ = handle(holder, isolate_); |
- return; |
+ break; |
} |
holder = maybe_holder; |
map = holder->map(); |
- state_ = LookupInHolder<is_element>(map, holder); |
+ state_ = LookupInHolder(map, holder); |
} while (!IsFound()); |
- holder_ = handle(holder, isolate_); |
+ if (holder != *holder_) holder_ = handle(holder, isolate_); |
} |
-template <bool is_element> |
+ |
void LookupIterator::RestartInternal(InterceptorState interceptor_state) { |
+ state_ = NOT_FOUND; |
interceptor_state_ = interceptor_state; |
property_details_ = PropertyDetails::Empty(); |
- Start<is_element>(); |
+ holder_ = initial_holder_; |
+ number_ = DescriptorArray::kNotFound; |
+ Next(); |
} |
-template void LookupIterator::RestartInternal<true>(InterceptorState); |
-template void LookupIterator::RestartInternal<false>(InterceptorState); |
// static |
Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( |
@@ -143,17 +116,29 @@ Handle<Map> LookupIterator::GetReceiverMap() const { |
return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); |
} |
+ |
+Handle<JSObject> LookupIterator::GetStoreTarget() const { |
+ if (receiver_->IsJSGlobalProxy()) { |
+ Object* prototype = JSGlobalProxy::cast(*receiver_)->map()->prototype(); |
+ if (!prototype->IsNull()) { |
+ return handle(JSGlobalObject::cast(prototype), isolate_); |
+ } |
+ } |
+ return Handle<JSObject>::cast(receiver_); |
+} |
+ |
+ |
bool LookupIterator::HasAccess() const { |
DCHECK_EQ(ACCESS_CHECK, state_); |
return isolate_->MayAccess(handle(isolate_->context()), |
GetHolder<JSObject>()); |
} |
-template <bool is_element> |
+ |
void LookupIterator::ReloadPropertyInformation() { |
state_ = BEFORE_PROPERTY; |
interceptor_state_ = InterceptorState::kUninitialized; |
- state_ = LookupInHolder<is_element>(holder_->map(), *holder_); |
+ state_ = LookupInHolder(holder_->map(), *holder_); |
DCHECK(IsFound() || !holder_->HasFastProperties()); |
} |
@@ -171,11 +156,14 @@ bool LookupIterator::HolderIsInContextIndex(uint32_t index) const { |
return false; |
} |
-void LookupIterator::InternalUpdateProtector() { |
+void LookupIterator::UpdateProtector() { |
+ if (!FLAG_harmony_species) return; |
+ |
+ if (IsElement()) return; |
if (isolate_->bootstrapper()->IsActive()) return; |
if (!isolate_->IsArraySpeciesLookupChainIntact()) return; |
- if (*name_ == heap()->constructor_string()) { |
+ if (*name_ == *isolate_->factory()->constructor_string()) { |
// Setting the constructor property could change an instance's @@species |
if (holder_->IsJSArray()) { |
isolate_->CountUsage( |
@@ -190,7 +178,7 @@ void LookupIterator::InternalUpdateProtector() { |
isolate_->InvalidateArraySpeciesProtector(); |
} |
} |
- } else if (*name_ == heap()->species_symbol()) { |
+ } else if (*name_ == *isolate_->factory()->species_symbol()) { |
// Setting the Symbol.species property of any Array constructor invalidates |
// the species protector |
if (HolderIsInContextIndex(Context::ARRAY_FUNCTION_INDEX)) { |
@@ -240,7 +228,7 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) { |
} |
JSObject::MigrateToMap(holder, new_map); |
- ReloadPropertyInformation<false>(); |
+ ReloadPropertyInformation(); |
} |
@@ -255,23 +243,19 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
Handle<FixedArrayBase> elements(holder->elements()); |
holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value, |
attributes); |
- ReloadPropertyInformation<true>(); |
+ } else if (!holder->HasFastProperties()) { |
+ PropertyDetails details(attributes, v8::internal::DATA, 0, |
+ PropertyCellType::kMutable); |
+ JSObject::SetNormalizedProperty(holder, name(), value, details); |
} else { |
- if (!holder->HasFastProperties()) { |
- PropertyDetails details(attributes, v8::internal::DATA, 0, |
- PropertyCellType::kMutable); |
- JSObject::SetNormalizedProperty(holder, name(), value, details); |
- } else { |
- Handle<Map> old_map(holder->map(), isolate_); |
- Handle<Map> new_map = Map::ReconfigureExistingProperty( |
- old_map, descriptor_number(), i::kData, attributes); |
- new_map = |
- Map::PrepareForDataProperty(new_map, descriptor_number(), value); |
- JSObject::MigrateToMap(holder, new_map); |
- } |
- ReloadPropertyInformation<false>(); |
+ Handle<Map> old_map(holder->map(), isolate_); |
+ Handle<Map> new_map = Map::ReconfigureExistingProperty( |
+ old_map, descriptor_number(), i::kData, attributes); |
+ new_map = Map::PrepareForDataProperty(new_map, descriptor_number(), value); |
+ JSObject::MigrateToMap(holder, new_map); |
} |
+ ReloadPropertyInformation(); |
WriteDataValue(value); |
#if VERIFY_HEAP |
@@ -339,7 +323,7 @@ void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) { |
property_details_ = transition->GetLastDescriptorDetails(); |
state_ = DATA; |
} else { |
- ReloadPropertyInformation<false>(); |
+ ReloadPropertyInformation(); |
} |
} |
@@ -358,7 +342,7 @@ void LookupIterator::Delete() { |
if (holder->HasFastProperties()) { |
JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0, |
"DeletingProperty"); |
- ReloadPropertyInformation<false>(); |
+ ReloadPropertyInformation(); |
} |
// TODO(verwaest): Get rid of the name_ argument. |
JSReceiver::DeleteNormalizedProperty(holder, name_, number_); |
@@ -386,7 +370,7 @@ void LookupIterator::TransitionToAccessorProperty( |
old_map, name_, component, accessor, attributes); |
JSObject::MigrateToMap(receiver, new_map); |
- ReloadPropertyInformation<false>(); |
+ ReloadPropertyInformation(); |
if (!new_map->is_dictionary_map()) return; |
} |
@@ -446,8 +430,6 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair, |
} else { |
receiver->set_elements(*dictionary); |
} |
- |
- ReloadPropertyInformation<true>(); |
} else { |
PropertyNormalizationMode mode = receiver->map()->is_prototype_map() |
? KEEP_INOBJECT_PROPERTIES |
@@ -458,9 +440,9 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair, |
JSObject::SetNormalizedProperty(receiver, name_, pair, details); |
JSObject::ReoptimizeIfPrototype(receiver); |
- |
- ReloadPropertyInformation<false>(); |
} |
+ |
+ ReloadPropertyInformation(); |
} |
@@ -600,6 +582,12 @@ void LookupIterator::WriteDataValue(Handle<Object> value) { |
} |
+bool LookupIterator::HasInterceptor(Map* map) const { |
+ if (IsElement()) return map->has_indexed_interceptor(); |
+ return map->has_named_interceptor(); |
+} |
+ |
+ |
bool LookupIterator::SkipInterceptor(JSObject* holder) { |
auto info = GetInterceptor(holder); |
// TODO(dcarney): check for symbol/can_intercept_symbols here as well. |
@@ -617,9 +605,10 @@ bool LookupIterator::SkipInterceptor(JSObject* holder) { |
return interceptor_state_ == InterceptorState::kProcessNonMasking; |
} |
+ |
JSReceiver* LookupIterator::NextHolder(Map* map) { |
DisallowHeapAllocation no_gc; |
- if (map->prototype() == heap()->null_value()) return NULL; |
+ if (!map->prototype()->IsJSReceiver()) return NULL; |
DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype()); |
@@ -646,37 +635,45 @@ LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const { |
: NOT_FOUND; |
} |
-namespace { |
- |
-template <bool is_element> |
-bool HasInterceptor(Map* map) { |
- return is_element ? map->has_indexed_interceptor() |
- : map->has_named_interceptor(); |
-} |
- |
-} // namespace |
- |
-template <bool is_element> |
-LookupIterator::State LookupIterator::LookupInSpecialHolder( |
- Map* const map, JSReceiver* const holder) { |
+LookupIterator::State LookupIterator::LookupInHolder(Map* const map, |
+ JSReceiver* const holder) { |
STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); |
+ DisallowHeapAllocation no_gc; |
+ if (interceptor_state_ == InterceptorState::kProcessNonMasking) { |
+ return LookupNonMaskingInterceptorInHolder(map, holder); |
+ } |
switch (state_) { |
case NOT_FOUND: |
if (map->IsJSProxyMap()) { |
- if (is_element || !name_->IsPrivate()) return JSPROXY; |
+ if (IsElement() || !name_->IsPrivate()) return JSPROXY; |
} |
if (map->is_access_check_needed()) { |
- if (is_element || !name_->IsPrivate()) return ACCESS_CHECK; |
+ if (IsElement() || !name_->IsPrivate()) return ACCESS_CHECK; |
} |
// Fall through. |
case ACCESS_CHECK: |
- if (check_interceptor() && HasInterceptor<is_element>(map) && |
+ if (check_interceptor() && HasInterceptor(map) && |
!SkipInterceptor(JSObject::cast(holder))) { |
- if (is_element || !name_->IsPrivate()) return INTERCEPTOR; |
+ if (IsElement() || !name_->IsPrivate()) return INTERCEPTOR; |
} |
// Fall through. |
case INTERCEPTOR: |
- if (!is_element && map->IsJSGlobalObjectMap()) { |
+ if (IsElement()) { |
+ JSObject* js_object = JSObject::cast(holder); |
+ ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
+ FixedArrayBase* backing_store = js_object->elements(); |
+ number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); |
+ if (number_ == kMaxUInt32) { |
+ return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; |
+ } |
+ property_details_ = accessor->GetDetails(js_object, number_); |
+ } else if (!map->is_dictionary_map()) { |
+ DescriptorArray* descriptors = map->instance_descriptors(); |
+ int number = descriptors->SearchWithCache(isolate_, *name_, map); |
+ if (number == DescriptorArray::kNotFound) return NotFound(holder); |
+ number_ = static_cast<uint32_t>(number); |
+ property_details_ = descriptors->GetDetails(number_); |
+ } else if (map->IsJSGlobalObjectMap()) { |
GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); |
int number = dict->FindEntry(name_); |
if (number == GlobalDictionary::kNotFound) return NOT_FOUND; |
@@ -685,15 +682,20 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder( |
PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); |
if (cell->value()->IsTheHole()) return NOT_FOUND; |
property_details_ = cell->property_details(); |
- has_property_ = true; |
- switch (property_details_.kind()) { |
- case v8::internal::kData: |
- return DATA; |
- case v8::internal::kAccessor: |
- return ACCESSOR; |
- } |
+ } else { |
+ NameDictionary* dict = holder->property_dictionary(); |
+ int number = dict->FindEntry(name_); |
+ if (number == NameDictionary::kNotFound) return NotFound(holder); |
+ number_ = static_cast<uint32_t>(number); |
+ property_details_ = dict->DetailsAt(number_); |
+ } |
+ has_property_ = true; |
+ switch (property_details_.kind()) { |
+ case v8::internal::kData: |
+ return DATA; |
+ case v8::internal::kAccessor: |
+ return ACCESSOR; |
} |
- return LookupInRegularHolder<is_element>(map, holder); |
case ACCESSOR: |
case DATA: |
return NOT_FOUND; |
@@ -703,47 +705,22 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder( |
UNREACHABLE(); |
} |
UNREACHABLE(); |
- return NOT_FOUND; |
+ return state_; |
} |
-template <bool is_element> |
-LookupIterator::State LookupIterator::LookupInRegularHolder( |
- Map* const map, JSReceiver* const holder) { |
- DisallowHeapAllocation no_gc; |
- if (interceptor_state_ == InterceptorState::kProcessNonMasking) { |
- return NOT_FOUND; |
- } |
- if (is_element) { |
- JSObject* js_object = JSObject::cast(holder); |
- ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
- FixedArrayBase* backing_store = js_object->elements(); |
- number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); |
- if (number_ == kMaxUInt32) { |
- return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; |
- } |
- property_details_ = accessor->GetDetails(js_object, number_); |
- } else if (!map->is_dictionary_map()) { |
- DescriptorArray* descriptors = map->instance_descriptors(); |
- int number = descriptors->SearchWithCache(isolate_, *name_, map); |
- if (number == DescriptorArray::kNotFound) return NotFound(holder); |
- number_ = static_cast<uint32_t>(number); |
- property_details_ = descriptors->GetDetails(number_); |
- } else { |
- NameDictionary* dict = holder->property_dictionary(); |
- int number = dict->FindEntry(name_); |
- if (number == NameDictionary::kNotFound) return NotFound(holder); |
- number_ = static_cast<uint32_t>(number); |
- property_details_ = dict->DetailsAt(number_); |
- } |
- has_property_ = true; |
- switch (property_details_.kind()) { |
- case v8::internal::kData: |
- return DATA; |
- case v8::internal::kAccessor: |
- return ACCESSOR; |
+LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder( |
+ Map* const map, JSReceiver* const holder) { |
+ switch (state_) { |
+ case NOT_FOUND: |
+ if (check_interceptor() && HasInterceptor(map) && |
+ !SkipInterceptor(JSObject::cast(holder))) { |
+ return INTERCEPTOR; |
+ } |
+ // Fall through. |
+ default: |
+ return NOT_FOUND; |
} |
- |
UNREACHABLE(); |
return state_; |
} |