Specialize helper methods in the LookupIterator by is_element.
This speeds up lookup. BUG= Review URL: https://codereview.chromium.org/1753273002 Cr-Commit-Position: refs/heads/master@{#34430}
This commit is contained in:
parent
2608ecc715
commit
6eb483f878
102
src/lookup.cc
102
src/lookup.cc
@ -45,6 +45,7 @@ LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
|
||||
return LookupIterator(receiver, name, configuration);
|
||||
}
|
||||
|
||||
template <bool is_element>
|
||||
void LookupIterator::Start() {
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
||||
@ -56,12 +57,15 @@ void LookupIterator::Start() {
|
||||
JSReceiver* holder = *holder_;
|
||||
Map* map = holder->map();
|
||||
|
||||
state_ = LookupInHolder(map, holder);
|
||||
state_ = LookupInHolder<is_element>(map, holder);
|
||||
if (IsFound()) return;
|
||||
|
||||
NextInternal(map, holder);
|
||||
NextInternal<is_element>(map, holder);
|
||||
}
|
||||
|
||||
template void LookupIterator::Start<true>();
|
||||
template void LookupIterator::Start<false>();
|
||||
|
||||
void LookupIterator::Next() {
|
||||
DCHECK_NE(JSPROXY, state_);
|
||||
DCHECK_NE(TRANSITION, state_);
|
||||
@ -72,19 +76,22 @@ void LookupIterator::Next() {
|
||||
Map* map = holder->map();
|
||||
|
||||
if (map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
|
||||
state_ = LookupInSpecialHolder(map, holder);
|
||||
state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder)
|
||||
: LookupInSpecialHolder<false>(map, holder);
|
||||
if (IsFound()) return;
|
||||
}
|
||||
|
||||
NextInternal(map, holder);
|
||||
IsElement() ? NextInternal<true>(map, holder)
|
||||
: NextInternal<false>(map, holder);
|
||||
}
|
||||
|
||||
template <bool is_element>
|
||||
void LookupIterator::NextInternal(Map* map, JSReceiver* holder) {
|
||||
do {
|
||||
JSReceiver* maybe_holder = NextHolder(map);
|
||||
if (maybe_holder == nullptr) {
|
||||
if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
|
||||
RestartLookupForNonMaskingInterceptors();
|
||||
RestartLookupForNonMaskingInterceptors<is_element>();
|
||||
return;
|
||||
}
|
||||
if (holder != *holder_) holder_ = handle(holder, isolate_);
|
||||
@ -92,18 +99,21 @@ void LookupIterator::NextInternal(Map* map, JSReceiver* holder) {
|
||||
}
|
||||
holder = maybe_holder;
|
||||
map = holder->map();
|
||||
state_ = LookupInHolder(map, holder);
|
||||
state_ = LookupInHolder<is_element>(map, holder);
|
||||
} while (!IsFound());
|
||||
|
||||
holder_ = handle(holder, isolate_);
|
||||
}
|
||||
|
||||
template <bool is_element>
|
||||
void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
|
||||
interceptor_state_ = interceptor_state;
|
||||
property_details_ = PropertyDetails::Empty();
|
||||
Start();
|
||||
Start<is_element>();
|
||||
}
|
||||
|
||||
template void LookupIterator::RestartInternal<true>(InterceptorState);
|
||||
template void LookupIterator::RestartInternal<false>(InterceptorState);
|
||||
|
||||
// static
|
||||
Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
|
||||
@ -139,11 +149,11 @@ bool LookupIterator::HasAccess() const {
|
||||
GetHolder<JSObject>());
|
||||
}
|
||||
|
||||
|
||||
template <bool is_element>
|
||||
void LookupIterator::ReloadPropertyInformation() {
|
||||
state_ = BEFORE_PROPERTY;
|
||||
interceptor_state_ = InterceptorState::kUninitialized;
|
||||
state_ = LookupInHolder(holder_->map(), *holder_);
|
||||
state_ = LookupInHolder<is_element>(holder_->map(), *holder_);
|
||||
DCHECK(IsFound() || !holder_->HasFastProperties());
|
||||
}
|
||||
|
||||
@ -168,7 +178,7 @@ void LookupIterator::UpdateProtector() {
|
||||
if (isolate_->bootstrapper()->IsActive()) return;
|
||||
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||
|
||||
if (*name_ == *isolate_->factory()->constructor_string()) {
|
||||
if (*name_ == heap()->constructor_string()) {
|
||||
// Setting the constructor property could change an instance's @@species
|
||||
if (holder_->IsJSArray()) {
|
||||
isolate_->CountUsage(
|
||||
@ -183,7 +193,7 @@ void LookupIterator::UpdateProtector() {
|
||||
isolate_->InvalidateArraySpeciesProtector();
|
||||
}
|
||||
}
|
||||
} else if (*name_ == *isolate_->factory()->species_symbol()) {
|
||||
} else if (*name_ == heap()->species_symbol()) {
|
||||
// Setting the Symbol.species property of any Array constructor invalidates
|
||||
// the species protector
|
||||
if (HolderIsInContextIndex(Context::ARRAY_FUNCTION_INDEX)) {
|
||||
@ -233,7 +243,7 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
|
||||
}
|
||||
|
||||
JSObject::MigrateToMap(holder, new_map);
|
||||
ReloadPropertyInformation();
|
||||
ReloadPropertyInformation<false>();
|
||||
}
|
||||
|
||||
|
||||
@ -248,19 +258,23 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
|
||||
Handle<FixedArrayBase> elements(holder->elements());
|
||||
holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value,
|
||||
attributes);
|
||||
} else if (!holder->HasFastProperties()) {
|
||||
PropertyDetails details(attributes, v8::internal::DATA, 0,
|
||||
PropertyCellType::kMutable);
|
||||
JSObject::SetNormalizedProperty(holder, name(), value, details);
|
||||
ReloadPropertyInformation<true>();
|
||||
} 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);
|
||||
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>();
|
||||
}
|
||||
|
||||
ReloadPropertyInformation();
|
||||
WriteDataValue(value);
|
||||
|
||||
#if VERIFY_HEAP
|
||||
@ -328,7 +342,7 @@ void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) {
|
||||
property_details_ = transition->GetLastDescriptorDetails();
|
||||
state_ = DATA;
|
||||
} else {
|
||||
ReloadPropertyInformation();
|
||||
ReloadPropertyInformation<false>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -347,7 +361,7 @@ void LookupIterator::Delete() {
|
||||
if (holder->HasFastProperties()) {
|
||||
JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
|
||||
"DeletingProperty");
|
||||
ReloadPropertyInformation();
|
||||
ReloadPropertyInformation<false>();
|
||||
}
|
||||
// TODO(verwaest): Get rid of the name_ argument.
|
||||
JSReceiver::DeleteNormalizedProperty(holder, name_, number_);
|
||||
@ -375,7 +389,7 @@ void LookupIterator::TransitionToAccessorProperty(
|
||||
old_map, name_, component, accessor, attributes);
|
||||
JSObject::MigrateToMap(receiver, new_map);
|
||||
|
||||
ReloadPropertyInformation();
|
||||
ReloadPropertyInformation<false>();
|
||||
|
||||
if (!new_map->is_dictionary_map()) return;
|
||||
}
|
||||
@ -435,6 +449,8 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
|
||||
} else {
|
||||
receiver->set_elements(*dictionary);
|
||||
}
|
||||
|
||||
ReloadPropertyInformation<true>();
|
||||
} else {
|
||||
PropertyNormalizationMode mode = receiver->map()->is_prototype_map()
|
||||
? KEEP_INOBJECT_PROPERTIES
|
||||
@ -445,9 +461,9 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
|
||||
|
||||
JSObject::SetNormalizedProperty(receiver, name_, pair, details);
|
||||
JSObject::ReoptimizeIfPrototype(receiver);
|
||||
}
|
||||
|
||||
ReloadPropertyInformation();
|
||||
ReloadPropertyInformation<false>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -587,12 +603,6 @@ 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.
|
||||
@ -639,26 +649,37 @@ 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) {
|
||||
STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
|
||||
switch (state_) {
|
||||
case NOT_FOUND:
|
||||
if (map->IsJSProxyMap()) {
|
||||
if (IsElement() || !name_->IsPrivate()) return JSPROXY;
|
||||
if (is_element || !name_->IsPrivate()) return JSPROXY;
|
||||
}
|
||||
if (map->is_access_check_needed()) {
|
||||
if (IsElement() || !name_->IsPrivate()) return ACCESS_CHECK;
|
||||
if (is_element || !name_->IsPrivate()) return ACCESS_CHECK;
|
||||
}
|
||||
// Fall through.
|
||||
case ACCESS_CHECK:
|
||||
if (check_interceptor() && HasInterceptor(map) &&
|
||||
if (check_interceptor() && HasInterceptor<is_element>(map) &&
|
||||
!SkipInterceptor(JSObject::cast(holder))) {
|
||||
if (IsElement() || !name_->IsPrivate()) return INTERCEPTOR;
|
||||
if (is_element || !name_->IsPrivate()) return INTERCEPTOR;
|
||||
}
|
||||
// Fall through.
|
||||
case INTERCEPTOR:
|
||||
if (!IsElement() && map->IsJSGlobalObjectMap()) {
|
||||
if (!is_element && map->IsJSGlobalObjectMap()) {
|
||||
GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary();
|
||||
int number = dict->FindEntry(name_);
|
||||
if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
|
||||
@ -675,7 +696,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder(
|
||||
return ACCESSOR;
|
||||
}
|
||||
}
|
||||
return LookupInRegularHolder(map, holder);
|
||||
return LookupInRegularHolder<is_element>(map, holder);
|
||||
case ACCESSOR:
|
||||
case DATA:
|
||||
return NOT_FOUND;
|
||||
@ -688,6 +709,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder(
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
template <bool is_element>
|
||||
LookupIterator::State LookupIterator::LookupInRegularHolder(
|
||||
Map* const map, JSReceiver* const holder) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
@ -695,7 +717,7 @@ LookupIterator::State LookupIterator::LookupInRegularHolder(
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
if (IsElement()) {
|
||||
if (is_element) {
|
||||
JSObject* js_object = JSObject::cast(holder);
|
||||
ElementsAccessor* accessor = js_object->GetElementsAccessor();
|
||||
FixedArrayBase* backing_store = js_object->elements();
|
||||
|
35
src/lookup.h
35
src/lookup.h
@ -59,7 +59,7 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
uint32_t index; // Assert that the name is not an array index.
|
||||
DCHECK(!name->AsArrayIndex(&index));
|
||||
#endif // DEBUG
|
||||
Start();
|
||||
Start<false>();
|
||||
}
|
||||
|
||||
LookupIterator(Handle<Object> receiver, Handle<Name> name,
|
||||
@ -78,7 +78,7 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
uint32_t index; // Assert that the name is not an array index.
|
||||
DCHECK(!name->AsArrayIndex(&index));
|
||||
#endif // DEBUG
|
||||
Start();
|
||||
Start<false>();
|
||||
}
|
||||
|
||||
LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
|
||||
@ -93,7 +93,7 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
initial_holder_(GetRoot(isolate, receiver, index)) {
|
||||
// kMaxUInt32 isn't a valid index.
|
||||
DCHECK_NE(kMaxUInt32, index_);
|
||||
Start();
|
||||
Start<true>();
|
||||
}
|
||||
|
||||
LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
|
||||
@ -109,7 +109,7 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
initial_holder_(holder) {
|
||||
// kMaxUInt32 isn't a valid index.
|
||||
DCHECK_NE(kMaxUInt32, index_);
|
||||
Start();
|
||||
Start<true>();
|
||||
}
|
||||
|
||||
static LookupIterator PropertyOrElement(
|
||||
@ -142,7 +142,10 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
|
||||
bool* success, Configuration configuration = DEFAULT);
|
||||
|
||||
void Restart() { RestartInternal(InterceptorState::kUninitialized); }
|
||||
void Restart() {
|
||||
InterceptorState state = InterceptorState::kUninitialized;
|
||||
IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
|
||||
}
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
State state() const { return state_; }
|
||||
@ -257,9 +260,6 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
void UpdateProtector();
|
||||
|
||||
private:
|
||||
void Start();
|
||||
void NextInternal(Map* map, JSReceiver* holder);
|
||||
|
||||
enum class InterceptorState {
|
||||
kUninitialized,
|
||||
kSkipNonMasking,
|
||||
@ -269,21 +269,32 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
Handle<Map> GetReceiverMap() const;
|
||||
|
||||
MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
|
||||
|
||||
template <bool is_element>
|
||||
void Start();
|
||||
template <bool is_element>
|
||||
void NextInternal(Map* map, JSReceiver* holder);
|
||||
template <bool is_element>
|
||||
inline State LookupInHolder(Map* map, JSReceiver* holder) {
|
||||
return map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE
|
||||
? LookupInSpecialHolder(map, holder)
|
||||
: LookupInRegularHolder(map, holder);
|
||||
? LookupInSpecialHolder<is_element>(map, holder)
|
||||
: LookupInRegularHolder<is_element>(map, holder);
|
||||
}
|
||||
template <bool is_element>
|
||||
State LookupInRegularHolder(Map* map, JSReceiver* holder);
|
||||
template <bool is_element>
|
||||
State LookupInSpecialHolder(Map* map, JSReceiver* holder);
|
||||
template <bool is_element>
|
||||
void RestartLookupForNonMaskingInterceptors() {
|
||||
RestartInternal(InterceptorState::kProcessNonMasking);
|
||||
RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
|
||||
}
|
||||
template <bool is_element>
|
||||
void RestartInternal(InterceptorState interceptor_state);
|
||||
Handle<Object> FetchValue() const;
|
||||
template <bool is_element>
|
||||
void ReloadPropertyInformation();
|
||||
|
||||
inline bool SkipInterceptor(JSObject* holder);
|
||||
bool HasInterceptor(Map* map) const;
|
||||
inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
|
||||
if (IsElement()) return holder->GetIndexedInterceptor();
|
||||
return holder->GetNamedInterceptor();
|
||||
|
Loading…
Reference in New Issue
Block a user