Commit 683223b4 authored by verwaest's avatar verwaest Committed by Commit bot

Reland "Speed up the LookupIterator"

BUG=

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

Cr-Commit-Position: refs/heads/master@{#34492}
parent 67838546
......@@ -7204,7 +7204,7 @@ class Internals {
static const int kNodeIsPartiallyDependentShift = 4;
static const int kNodeIsActiveShift = 4;
static const int kJSObjectType = 0xb5;
static const int kJSObjectType = 0xb8;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x83;
static const int kForeignType = 0x87;
......
......@@ -542,7 +542,13 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
InstanceType type;
switch (instance_type) {
case JavaScriptObjectType:
type = JS_OBJECT_TYPE;
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;
}
instance_size += JSObject::kHeaderSize;
break;
case GlobalObjectType:
......
......@@ -3575,11 +3575,12 @@ AllocationResult Heap::CopyJSObject(JSObject* source, AllocationSite* site) {
// Make the clone.
Map* map = source->map();
// We can only clone regexps, normal objects or arrays. Copying anything else
// will break invariants.
// We can only clone regexps, normal objects, api 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_ARRAY_TYPE ||
map->instance_type() == JS_SPECIAL_API_OBJECT_TYPE);
int object_size = map->instance_size();
HeapObject* clone = nullptr;
......
......@@ -111,6 +111,7 @@ 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:
......
This diff is collapsed.
......@@ -47,7 +47,6 @@ 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()),
......@@ -55,21 +54,18 @@ class LookupIterator final BASE_EMBEDDED {
// kMaxUInt32 isn't a valid index.
index_(kMaxUInt32),
receiver_(receiver),
holder_(GetRoot(isolate_, receiver)),
initial_holder_(holder_),
number_(DescriptorArray::kNotFound) {
initial_holder_(GetRoot(isolate_, receiver)) {
#ifdef DEBUG
uint32_t index; // Assert that the name is not an array index.
DCHECK(!name->AsArrayIndex(&index));
#endif // DEBUG
Next();
Start<false>();
}
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()),
......@@ -77,51 +73,43 @@ class LookupIterator final BASE_EMBEDDED {
// kMaxUInt32 isn't a valid index.
index_(kMaxUInt32),
receiver_(receiver),
holder_(holder),
initial_holder_(holder_),
number_(DescriptorArray::kNotFound) {
initial_holder_(holder) {
#ifdef DEBUG
uint32_t index; // Assert that the name is not an array index.
DCHECK(!name->AsArrayIndex(&index));
#endif // DEBUG
Next();
Start<false>();
}
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),
holder_(GetRoot(isolate, receiver, index)),
initial_holder_(holder_),
number_(DescriptorArray::kNotFound) {
initial_holder_(GetRoot(isolate, receiver, index)) {
// kMaxUInt32 isn't a valid index.
DCHECK_NE(kMaxUInt32, index_);
Next();
Start<true>();
}
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),
holder_(holder),
initial_holder_(holder_),
number_(DescriptorArray::kNotFound) {
initial_holder_(holder) {
// kMaxUInt32 isn't a valid index.
DCHECK_NE(kMaxUInt32, index_);
Next();
Start<true>();
}
static LookupIterator PropertyOrElement(
......@@ -154,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_; }
......@@ -184,7 +175,17 @@ 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;
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_);
}
bool is_dictionary_holder() const { return !holder_->HasFastProperties(); }
Handle<Map> transition_map() const {
DCHECK_EQ(TRANSITION, state_);
......@@ -256,9 +257,17 @@ class LookupIterator final BASE_EMBEDDED {
}
Handle<Object> GetDataValue() const;
void WriteDataValue(Handle<Object> value);
void UpdateProtector();
inline void UpdateProtector() {
if (FLAG_harmony_species && !IsElement() &&
(*name_ == heap()->constructor_string() ||
*name_ == heap()->species_symbol())) {
InternalUpdateProtector();
}
}
private:
void InternalUpdateProtector();
enum class InterceptorState {
kUninitialized,
kSkipNonMasking,
......@@ -268,16 +277,32 @@ class LookupIterator final BASE_EMBEDDED {
Handle<Map> GetReceiverMap() const;
MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
inline State LookupInHolder(Map* map, JSReceiver* holder);
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>
void RestartLookupForNonMaskingInterceptors() {
RestartInternal(InterceptorState::kProcessNonMasking);
RestartInternal<is_element>(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,6 +472,7 @@ 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,6 +99,7 @@ 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();
......
......@@ -1959,6 +1959,8 @@ 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,6 +95,7 @@ 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:
......
......@@ -4129,7 +4129,7 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
LanguageMode language_mode,
StoreFromKeyed store_mode,
bool* found) {
it->UpdateProtector();
DCHECK(it->IsFound());
ShouldThrow should_throw =
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
......@@ -4137,7 +4137,7 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
// interceptor calls.
AssertNoContextChange ncc(it->isolate());
for (; it->IsFound(); it->Next()) {
do {
switch (it->state()) {
case LookupIterator::NOT_FOUND:
UNREACHABLE();
......@@ -4200,7 +4200,8 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
*found = false;
return Nothing<bool>();
}
}
it->Next();
} while (it->IsFound());
*found = false;
return Nothing<bool>();
......@@ -4210,10 +4211,13 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
LanguageMode language_mode,
StoreFromKeyed store_mode) {
bool found = true;
Maybe<bool> result =
SetPropertyInternal(it, value, language_mode, store_mode, &found);
if (found) return result;
it->UpdateProtector();
if (it->IsFound()) {
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
......@@ -4235,10 +4239,13 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
StoreFromKeyed store_mode) {
Isolate* isolate = it->isolate();
bool found = true;
Maybe<bool> result =
SetPropertyInternal(it, value, language_mode, store_mode, &found);
if (found) return result;
it->UpdateProtector();
if (it->IsFound()) {
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.
......@@ -4313,8 +4320,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
}
}
return JSObject::AddDataProperty(&own_lookup, value, NONE, should_throw,
store_mode);
return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
}
MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it) {
......@@ -8373,9 +8379,8 @@ 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()) &&
!is_access_check_needed() && !has_named_interceptor() &&
!has_indexed_interceptor() && !has_hidden_prototype() &&
!is_dictionary_map();
instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
!has_hidden_prototype() && !is_dictionary_map();
}
namespace {
......
......@@ -419,6 +419,7 @@ 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) \
......@@ -438,7 +439,6 @@ 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,7 +591,6 @@ static inline bool IsShortcutCandidate(int type) {
return ((type & kShortcutTypeMask) == kShortcutTypeTag);
}
enum InstanceType {
// String types.
INTERNALIZED_STRING_TYPE = kTwoByteStringTag | kSeqStringTag |
......@@ -703,16 +702,18 @@ 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_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE
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_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,
......@@ -753,8 +754,10 @@ 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_VALUE_TYPE,
FIRST_JS_OBJECT_TYPE = JS_GLOBAL_OBJECT_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,6 +201,7 @@ 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:
......
// Copyright 2016 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.
var g = Realm.global(Realm.create());
assertThrows(()=>g.toString());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment