v8/src/lookup-inl.h
verwaest 78ef2e5b29 Micro-optimize lookupiterator: faster path for fast-mode objects
BUG=chromium:505998
LOG=n

Review URL: https://codereview.chromium.org/1222543003

Cr-Commit-Position: refs/heads/master@{#29419}
2015-07-01 14:19:02 +00:00

142 lines
4.8 KiB
C++

// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_LOOKUP_INL_H_
#define V8_LOOKUP_INL_H_
#include "src/lookup.h"
#include "src/elements.h"
namespace v8 {
namespace internal {
JSReceiver* LookupIterator::NextHolder(Map* map) {
DisallowHeapAllocation no_gc;
if (!map->prototype()->IsJSReceiver()) return NULL;
JSReceiver* next = JSReceiver::cast(map->prototype());
DCHECK(!next->map()->IsGlobalObjectMap() ||
next->map()->is_hidden_prototype());
if (!check_prototype_chain() &&
!(check_hidden() && next->map()->is_hidden_prototype()) &&
// Always lookup behind the JSGlobalProxy into the JSGlobalObject, even
// when not checking other hidden prototypes.
!map->IsJSGlobalProxyMap()) {
return NULL;
}
return next;
}
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()) return JSPROXY;
if (map->is_access_check_needed() &&
(IsElement() || !isolate_->IsInternallyUsedPropertyName(name_))) {
return ACCESS_CHECK;
}
// Fall through.
case ACCESS_CHECK:
if (exotic_index_state_ != ExoticIndexState::kNotExotic &&
IsIntegerIndexedExotic(holder)) {
return INTEGER_INDEXED_EXOTIC;
}
if (check_interceptor() && HasInterceptor(map) &&
!SkipInterceptor(JSObject::cast(holder))) {
return INTERCEPTOR;
}
// Fall through.
case INTERCEPTOR:
if (IsElement()) {
// TODO(verwaest): Optimize.
if (holder->IsStringObjectWithCharacterAt(index_)) {
PropertyAttributes attributes =
static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
property_details_ = PropertyDetails(attributes, v8::internal::DATA, 0,
PropertyCellType::kNoCell);
} else {
JSObject* js_object = JSObject::cast(holder);
if (js_object->elements() == isolate()->heap()->empty_fixed_array()) {
return NOT_FOUND;
}
ElementsAccessor* accessor = js_object->GetElementsAccessor();
FixedArrayBase* backing_store = js_object->elements();
number_ = accessor->GetIndexForKey(js_object, backing_store, index_);
if (number_ == kMaxUInt32) return NOT_FOUND;
property_details_ = accessor->GetDetails(backing_store, number_);
}
} else if (!map->is_dictionary_map()) {
DescriptorArray* descriptors = map->instance_descriptors();
int number = descriptors->SearchWithCache(*name_, map);
if (number == DescriptorArray::kNotFound) return NOT_FOUND;
number_ = static_cast<uint32_t>(number);
property_details_ = descriptors->GetDetails(number_);
} else if (map->IsGlobalObjectMap()) {
GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary();
int number = dict->FindEntry(name_);
if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
number_ = static_cast<uint32_t>(number);
DCHECK(dict->ValueAt(number_)->IsPropertyCell());
PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
if (cell->value()->IsTheHole()) return NOT_FOUND;
property_details_ = cell->property_details();
} else {
NameDictionary* dict = JSObject::cast(holder)->property_dictionary();
int number = dict->FindEntry(name_);
if (number == NameDictionary::kNotFound) return NOT_FOUND;
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;
}
case ACCESSOR:
case DATA:
return NOT_FOUND;
case INTEGER_INDEXED_EXOTIC:
case JSPROXY:
case TRANSITION:
UNREACHABLE();
}
UNREACHABLE();
return state_;
}
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_;
}
}
} // namespace v8::internal
#endif // V8_LOOKUP_INL_H_