Revert "Speed up the LookupIterator"
This reverts commit2608ecc715
. Revert "Specialize helper methods in the LookupIterator by is_element." This reverts commit6eb483f878
. Revert "Avoid SetPropertyInternal if the LookupIterator is NotFound" This reverts commitca5bd8d4a9
. Revert "Inline fast-bailout-checks for LookupIterator::UpdateProtector" This reverts commitd98570a1eb
. This breaks layout tests with timeouts: https://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2064/builds/5060 It also seems to break jsfunfuzz: https://build.chromium.org/p/client.v8/builders/V8%20Fuzzer/builds/7930 The other three CLs are reverted to be able to revert the first. BUG=v8:4798 LOG=n TBR=verwaest@chromium.org Review URL: https://codereview.chromium.org/1761593003 Cr-Commit-Position: refs/heads/master@{#34457}
This commit is contained in:
parent
e982f95023
commit
70ac41a84a
@ -7203,7 +7203,7 @@ class Internals {
|
||||
static const int kNodeIsPartiallyDependentShift = 4;
|
||||
static const int kNodeIsActiveShift = 4;
|
||||
|
||||
static const int kJSObjectType = 0xb8;
|
||||
static const int kJSObjectType = 0xb5;
|
||||
static const int kFirstNonstringType = 0x80;
|
||||
static const int kOddballType = 0x83;
|
||||
static const int kForeignType = 0x87;
|
||||
|
@ -542,13 +542,7 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
|
||||
InstanceType type;
|
||||
switch (instance_type) {
|
||||
case JavaScriptObjectType:
|
||||
if (!obj->needs_access_check() &&
|
||||
obj->named_property_handler()->IsUndefined() &&
|
||||
obj->indexed_property_handler()->IsUndefined()) {
|
||||
type = JS_OBJECT_TYPE;
|
||||
} else {
|
||||
type = JS_SPECIAL_API_OBJECT_TYPE;
|
||||
}
|
||||
type = JS_OBJECT_TYPE;
|
||||
instance_size += JSObject::kHeaderSize;
|
||||
break;
|
||||
case GlobalObjectType:
|
||||
|
@ -3575,12 +3575,11 @@ AllocationResult Heap::CopyJSObject(JSObject* source, AllocationSite* site) {
|
||||
// Make the clone.
|
||||
Map* map = source->map();
|
||||
|
||||
// We can only clone regexps, normal objects, api objects or arrays. Copying
|
||||
// anything else will break invariants.
|
||||
// We can only clone regexps, normal objects or arrays. Copying anything else
|
||||
// will break invariants.
|
||||
CHECK(map->instance_type() == JS_REGEXP_TYPE ||
|
||||
map->instance_type() == JS_OBJECT_TYPE ||
|
||||
map->instance_type() == JS_ARRAY_TYPE ||
|
||||
map->instance_type() == JS_SPECIAL_API_OBJECT_TYPE);
|
||||
map->instance_type() == JS_ARRAY_TYPE);
|
||||
|
||||
int object_size = map->instance_size();
|
||||
HeapObject* clone = nullptr;
|
||||
|
@ -111,7 +111,6 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
case JS_ARRAY_TYPE:
|
||||
case JS_GLOBAL_PROXY_TYPE:
|
||||
case JS_GLOBAL_OBJECT_TYPE:
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_MESSAGE_OBJECT_TYPE:
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
case JS_DATA_VIEW_TYPE:
|
||||
|
239
src/lookup.cc
239
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;
|
||||
}
|
||||
// Perform lookup on current holder.
|
||||
state_ = LookupInHolder(map, holder);
|
||||
if (IsFound()) return;
|
||||
|
||||
IsElement() ? NextInternal<true>(map, holder)
|
||||
: NextInternal<false>(map, holder);
|
||||
}
|
||||
|
||||
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(
|
||||
|
||||
LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder(
|
||||
Map* const map, JSReceiver* const holder) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
|
||||
return NOT_FOUND;
|
||||
switch (state_) {
|
||||
case NOT_FOUND:
|
||||
if (check_interceptor() && HasInterceptor(map) &&
|
||||
!SkipInterceptor(JSObject::cast(holder))) {
|
||||
return INTERCEPTOR;
|
||||
}
|
||||
// Fall through.
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return state_;
|
||||
}
|
||||
|
79
src/lookup.h
79
src/lookup.h
@ -47,6 +47,7 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
LookupIterator(Handle<Object> receiver, Handle<Name> name,
|
||||
Configuration configuration = DEFAULT)
|
||||
: configuration_(ComputeConfiguration(configuration, name)),
|
||||
state_(NOT_FOUND),
|
||||
interceptor_state_(InterceptorState::kUninitialized),
|
||||
property_details_(PropertyDetails::Empty()),
|
||||
isolate_(name->GetIsolate()),
|
||||
@ -54,18 +55,21 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
// kMaxUInt32 isn't a valid index.
|
||||
index_(kMaxUInt32),
|
||||
receiver_(receiver),
|
||||
initial_holder_(GetRoot(isolate_, receiver)) {
|
||||
holder_(GetRoot(isolate_, receiver)),
|
||||
initial_holder_(holder_),
|
||||
number_(DescriptorArray::kNotFound) {
|
||||
#ifdef DEBUG
|
||||
uint32_t index; // Assert that the name is not an array index.
|
||||
DCHECK(!name->AsArrayIndex(&index));
|
||||
#endif // DEBUG
|
||||
Start<false>();
|
||||
Next();
|
||||
}
|
||||
|
||||
LookupIterator(Handle<Object> receiver, Handle<Name> name,
|
||||
Handle<JSReceiver> holder,
|
||||
Configuration configuration = DEFAULT)
|
||||
: configuration_(ComputeConfiguration(configuration, name)),
|
||||
state_(NOT_FOUND),
|
||||
interceptor_state_(InterceptorState::kUninitialized),
|
||||
property_details_(PropertyDetails::Empty()),
|
||||
isolate_(name->GetIsolate()),
|
||||
@ -73,43 +77,51 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
// kMaxUInt32 isn't a valid index.
|
||||
index_(kMaxUInt32),
|
||||
receiver_(receiver),
|
||||
initial_holder_(holder) {
|
||||
holder_(holder),
|
||||
initial_holder_(holder_),
|
||||
number_(DescriptorArray::kNotFound) {
|
||||
#ifdef DEBUG
|
||||
uint32_t index; // Assert that the name is not an array index.
|
||||
DCHECK(!name->AsArrayIndex(&index));
|
||||
#endif // DEBUG
|
||||
Start<false>();
|
||||
Next();
|
||||
}
|
||||
|
||||
LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
|
||||
Configuration configuration = DEFAULT)
|
||||
: configuration_(configuration),
|
||||
state_(NOT_FOUND),
|
||||
interceptor_state_(InterceptorState::kUninitialized),
|
||||
property_details_(PropertyDetails::Empty()),
|
||||
isolate_(isolate),
|
||||
name_(),
|
||||
index_(index),
|
||||
receiver_(receiver),
|
||||
initial_holder_(GetRoot(isolate, receiver, index)) {
|
||||
holder_(GetRoot(isolate, receiver, index)),
|
||||
initial_holder_(holder_),
|
||||
number_(DescriptorArray::kNotFound) {
|
||||
// kMaxUInt32 isn't a valid index.
|
||||
DCHECK_NE(kMaxUInt32, index_);
|
||||
Start<true>();
|
||||
Next();
|
||||
}
|
||||
|
||||
LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
|
||||
Handle<JSReceiver> holder,
|
||||
Configuration configuration = DEFAULT)
|
||||
: configuration_(configuration),
|
||||
state_(NOT_FOUND),
|
||||
interceptor_state_(InterceptorState::kUninitialized),
|
||||
property_details_(PropertyDetails::Empty()),
|
||||
isolate_(isolate),
|
||||
name_(),
|
||||
index_(index),
|
||||
receiver_(receiver),
|
||||
initial_holder_(holder) {
|
||||
holder_(holder),
|
||||
initial_holder_(holder_),
|
||||
number_(DescriptorArray::kNotFound) {
|
||||
// kMaxUInt32 isn't a valid index.
|
||||
DCHECK_NE(kMaxUInt32, index_);
|
||||
Start<true>();
|
||||
Next();
|
||||
}
|
||||
|
||||
static LookupIterator PropertyOrElement(
|
||||
@ -142,10 +154,7 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
|
||||
bool* success, Configuration configuration = DEFAULT);
|
||||
|
||||
void Restart() {
|
||||
InterceptorState state = InterceptorState::kUninitialized;
|
||||
IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
|
||||
}
|
||||
void Restart() { RestartInternal(InterceptorState::kUninitialized); }
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
State state() const { return state_; }
|
||||
@ -175,17 +184,7 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
Heap* heap() const { return isolate_->heap(); }
|
||||
Factory* factory() const { return isolate_->factory(); }
|
||||
Handle<Object> GetReceiver() const { return receiver_; }
|
||||
|
||||
Handle<JSObject> GetStoreTarget() const {
|
||||
if (receiver_->IsJSGlobalProxy()) {
|
||||
Map* map = JSGlobalProxy::cast(*receiver_)->map();
|
||||
if (map->has_hidden_prototype()) {
|
||||
return handle(JSGlobalObject::cast(map->prototype()), isolate_);
|
||||
}
|
||||
}
|
||||
return Handle<JSObject>::cast(receiver_);
|
||||
}
|
||||
|
||||
Handle<JSObject> GetStoreTarget() const;
|
||||
bool is_dictionary_holder() const { return !holder_->HasFastProperties(); }
|
||||
Handle<Map> transition_map() const {
|
||||
DCHECK_EQ(TRANSITION, state_);
|
||||
@ -257,17 +256,9 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
}
|
||||
Handle<Object> GetDataValue() const;
|
||||
void WriteDataValue(Handle<Object> value);
|
||||
inline void UpdateProtector() {
|
||||
if (FLAG_harmony_species && !IsElement() &&
|
||||
(*name_ == heap()->constructor_string() ||
|
||||
*name_ == heap()->species_symbol())) {
|
||||
InternalUpdateProtector();
|
||||
}
|
||||
}
|
||||
void UpdateProtector();
|
||||
|
||||
private:
|
||||
void InternalUpdateProtector();
|
||||
|
||||
enum class InterceptorState {
|
||||
kUninitialized,
|
||||
kSkipNonMasking,
|
||||
@ -277,32 +268,16 @@ 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<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>
|
||||
inline State LookupInHolder(Map* map, JSReceiver* holder);
|
||||
void RestartLookupForNonMaskingInterceptors() {
|
||||
RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
|
||||
RestartInternal(InterceptorState::kProcessNonMasking);
|
||||
}
|
||||
template <bool is_element>
|
||||
void RestartInternal(InterceptorState interceptor_state);
|
||||
State LookupNonMaskingInterceptorInHolder(Map* map, JSReceiver* holder);
|
||||
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();
|
||||
|
@ -472,7 +472,6 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) {
|
||||
case JS_REGEXP_TYPE:
|
||||
case JS_GLOBAL_PROXY_TYPE:
|
||||
case JS_GLOBAL_OBJECT_TYPE:
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_MESSAGE_OBJECT_TYPE:
|
||||
case JS_BOUND_FUNCTION_TYPE:
|
||||
return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3);
|
||||
|
@ -99,7 +99,6 @@ void HeapObject::HeapObjectVerify() {
|
||||
Oddball::cast(this)->OddballVerify();
|
||||
break;
|
||||
case JS_OBJECT_TYPE:
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
||||
case JS_PROMISE_TYPE:
|
||||
JSObject::cast(this)->JSObjectVerify();
|
||||
|
@ -1961,8 +1961,6 @@ int JSObject::GetHeaderSize(InstanceType type) {
|
||||
// field operations considerably on average.
|
||||
if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize;
|
||||
switch (type) {
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
return JSObject::kHeaderSize;
|
||||
case JS_GENERATOR_OBJECT_TYPE:
|
||||
return JSGeneratorObject::kSize;
|
||||
case JS_MODULE_TYPE:
|
||||
|
@ -95,7 +95,6 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
|
||||
os << "filler";
|
||||
break;
|
||||
case JS_OBJECT_TYPE: // fall through
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
||||
case JS_ARRAY_TYPE:
|
||||
case JS_GENERATOR_OBJECT_TYPE:
|
||||
|
@ -4131,7 +4131,7 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
|
||||
LanguageMode language_mode,
|
||||
StoreFromKeyed store_mode,
|
||||
bool* found) {
|
||||
DCHECK(it->IsFound());
|
||||
it->UpdateProtector();
|
||||
ShouldThrow should_throw =
|
||||
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
|
||||
|
||||
@ -4139,7 +4139,7 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
|
||||
// interceptor calls.
|
||||
AssertNoContextChange ncc(it->isolate());
|
||||
|
||||
do {
|
||||
for (; it->IsFound(); it->Next()) {
|
||||
switch (it->state()) {
|
||||
case LookupIterator::NOT_FOUND:
|
||||
UNREACHABLE();
|
||||
@ -4202,8 +4202,7 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
|
||||
*found = false;
|
||||
return Nothing<bool>();
|
||||
}
|
||||
it->Next();
|
||||
} while (it->IsFound());
|
||||
}
|
||||
|
||||
*found = false;
|
||||
return Nothing<bool>();
|
||||
@ -4213,13 +4212,10 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
|
||||
Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
|
||||
LanguageMode language_mode,
|
||||
StoreFromKeyed store_mode) {
|
||||
it->UpdateProtector();
|
||||
if (it->IsFound()) {
|
||||
bool found = true;
|
||||
Maybe<bool> result =
|
||||
SetPropertyInternal(it, value, language_mode, store_mode, &found);
|
||||
if (found) return result;
|
||||
}
|
||||
bool found = true;
|
||||
Maybe<bool> result =
|
||||
SetPropertyInternal(it, value, language_mode, store_mode, &found);
|
||||
if (found) return result;
|
||||
|
||||
// If the receiver is the JSGlobalObject, the store was contextual. In case
|
||||
// the property did not exist yet on the global object itself, we have to
|
||||
@ -4241,13 +4237,10 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
|
||||
StoreFromKeyed store_mode) {
|
||||
Isolate* isolate = it->isolate();
|
||||
|
||||
it->UpdateProtector();
|
||||
if (it->IsFound()) {
|
||||
bool found = true;
|
||||
Maybe<bool> result =
|
||||
SetPropertyInternal(it, value, language_mode, store_mode, &found);
|
||||
if (found) return result;
|
||||
}
|
||||
bool found = true;
|
||||
Maybe<bool> result =
|
||||
SetPropertyInternal(it, value, language_mode, store_mode, &found);
|
||||
if (found) return result;
|
||||
|
||||
// The property either doesn't exist on the holder or exists there as a data
|
||||
// property.
|
||||
@ -4322,7 +4315,8 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
|
||||
}
|
||||
}
|
||||
|
||||
return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
|
||||
return JSObject::AddDataProperty(&own_lookup, value, NONE, should_throw,
|
||||
store_mode);
|
||||
}
|
||||
|
||||
MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it) {
|
||||
@ -8381,8 +8375,9 @@ bool Map::OnlyHasSimpleProperties() {
|
||||
// Wrapped string elements aren't explicitly stored in the elements backing
|
||||
// store, but are loaded indirectly from the underlying string.
|
||||
return !IsStringWrapperElementsKind(elements_kind()) &&
|
||||
instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
|
||||
!has_hidden_prototype() && !is_dictionary_map();
|
||||
!is_access_check_needed() && !has_named_interceptor() &&
|
||||
!has_indexed_interceptor() && !has_hidden_prototype() &&
|
||||
!is_dictionary_map();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -419,7 +419,6 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(JS_MODULE_TYPE) \
|
||||
V(JS_GLOBAL_OBJECT_TYPE) \
|
||||
V(JS_GLOBAL_PROXY_TYPE) \
|
||||
V(JS_SPECIAL_API_OBJECT_TYPE) \
|
||||
V(JS_ARRAY_TYPE) \
|
||||
V(JS_ARRAY_BUFFER_TYPE) \
|
||||
V(JS_TYPED_ARRAY_TYPE) \
|
||||
@ -439,6 +438,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(DEBUG_INFO_TYPE) \
|
||||
V(BREAK_POINT_INFO_TYPE)
|
||||
|
||||
|
||||
// Since string types are not consecutive, this macro is used to
|
||||
// iterate over them.
|
||||
#define STRING_TYPE_LIST(V) \
|
||||
@ -591,6 +591,7 @@ static inline bool IsShortcutCandidate(int type) {
|
||||
return ((type & kShortcutTypeMask) == kShortcutTypeTag);
|
||||
}
|
||||
|
||||
|
||||
enum InstanceType {
|
||||
// String types.
|
||||
INTERNALIZED_STRING_TYPE = kTwoByteStringTag | kSeqStringTag |
|
||||
@ -702,18 +703,16 @@ enum InstanceType {
|
||||
// objects in the JS sense. The first and the last type in this range are
|
||||
// the two forms of function. This organization enables using the same
|
||||
// compares for checking the JS_RECEIVER and the NONCALLABLE_JS_OBJECT range.
|
||||
JS_PROXY_TYPE, // FIRST_JS_RECEIVER_TYPE
|
||||
JS_GLOBAL_OBJECT_TYPE, // FIRST_JS_OBJECT_TYPE
|
||||
JS_GLOBAL_PROXY_TYPE,
|
||||
// Like JS_OBJECT_TYPE, but requires access checks and/or has interceptors.
|
||||
JS_SPECIAL_API_OBJECT_TYPE, // LAST_SPECIAL_RECEIVER_TYPE
|
||||
JS_VALUE_TYPE,
|
||||
JS_PROXY_TYPE, // FIRST_JS_RECEIVER_TYPE
|
||||
JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE
|
||||
JS_MESSAGE_OBJECT_TYPE,
|
||||
JS_DATE_TYPE,
|
||||
JS_OBJECT_TYPE,
|
||||
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
|
||||
JS_GENERATOR_OBJECT_TYPE,
|
||||
JS_MODULE_TYPE,
|
||||
JS_GLOBAL_OBJECT_TYPE,
|
||||
JS_GLOBAL_PROXY_TYPE,
|
||||
JS_ARRAY_TYPE,
|
||||
JS_ARRAY_BUFFER_TYPE,
|
||||
JS_TYPED_ARRAY_TYPE,
|
||||
@ -754,10 +753,8 @@ enum InstanceType {
|
||||
FIRST_JS_RECEIVER_TYPE = JS_PROXY_TYPE,
|
||||
LAST_JS_RECEIVER_TYPE = LAST_TYPE,
|
||||
// Boundaries for testing the types represented as JSObject
|
||||
FIRST_JS_OBJECT_TYPE = JS_GLOBAL_OBJECT_TYPE,
|
||||
FIRST_JS_OBJECT_TYPE = JS_VALUE_TYPE,
|
||||
LAST_JS_OBJECT_TYPE = LAST_TYPE,
|
||||
// Boundary for testing JSReceivers that need special property lookup handling
|
||||
LAST_SPECIAL_RECEIVER_TYPE = JS_SPECIAL_API_OBJECT_TYPE,
|
||||
};
|
||||
|
||||
STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);
|
||||
|
@ -201,7 +201,6 @@ Type::bitset BitsetType::Lub(i::Map* map) {
|
||||
case JS_OBJECT_TYPE:
|
||||
case JS_GLOBAL_OBJECT_TYPE:
|
||||
case JS_GLOBAL_PROXY_TYPE:
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
if (map->is_undetectable()) return kOtherUndetectable;
|
||||
return kOtherObject;
|
||||
case JS_VALUE_TYPE:
|
||||
|
Loading…
Reference in New Issue
Block a user