[feedback] Introduce FeedbackSlotIterator

FeedbackSlotIterator abstracts over the different IC states and
provides an unified interface to iterate over the map and handlers in
the IC.

Bug: v8:10582
Change-Id: I67861bfbd33d82e8b1ad06156fbf6fd72775321c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2349295
Commit-Queue: Sathya Gunasekaran  <gsathya@chromium.org>
Reviewed-by: Mythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69357}
This commit is contained in:
Sathya Gunasekaran 2020-08-12 11:33:31 +01:00 committed by Commit Bot
parent 2e37bfc5b9
commit 175e982e5a
2 changed files with 148 additions and 168 deletions

View File

@ -588,9 +588,11 @@ bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
}
Map FeedbackNexus::GetFirstMap() const {
MapHandles maps;
ExtractMaps(&maps);
if (!maps.empty()) return *maps.at(0);
FeedbackIterator it(this);
if (!it.done()) {
return it.map();
}
return Map();
}
@ -964,187 +966,72 @@ void FeedbackNexus::ConfigurePolymorphic(
}
int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
DisallowHeapAllocation no_gc;
Isolate* isolate = GetIsolate();
MaybeObject feedback = GetFeedback();
bool is_named_feedback = IsPropertyNameFeedback(feedback);
HeapObject heap_object;
if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
heap_object.IsWeakFixedArray()) ||
is_named_feedback) {
int found = 0;
WeakFixedArray array;
if (is_named_feedback) {
array =
WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
} else {
array = WeakFixedArray::cast(heap_object);
}
const int increment = 2;
HeapObject heap_object;
for (int i = 0; i < array.length(); i += increment) {
DCHECK(array.Get(i)->IsWeakOrCleared());
if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) {
Map map = Map::cast(heap_object);
maps->push_back(handle(map, isolate));
found++;
}
}
return found;
} else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
Map map = Map::cast(heap_object);
maps->push_back(handle(map, isolate));
return 1;
int found = 0;
for (FeedbackIterator it(this); !it.done(); it.Advance()) {
maps->push_back(handle(it.map(), isolate));
found++;
}
return 0;
}
int FeedbackNexus::ExtractMapsAndFeedbackImpl(
std::vector<MapAndFeedback>* maps_and_feedback,
bool try_update_deprecated) const {
DCHECK(IsLoadICKind(kind()) ||
IsStoreICKind(kind()) | IsKeyedLoadICKind(kind()) ||
IsKeyedStoreICKind(kind()) || IsStoreOwnICKind(kind()) ||
IsStoreDataPropertyInLiteralKind(kind()) ||
IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
DisallowHeapAllocation no_gc;
Isolate* isolate = GetIsolate();
MaybeObject feedback = GetFeedback();
bool is_named_feedback = IsPropertyNameFeedback(feedback);
HeapObject heap_object;
if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
heap_object.IsWeakFixedArray()) ||
is_named_feedback) {
int found = 0;
WeakFixedArray array;
if (is_named_feedback) {
array =
WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
} else {
array = WeakFixedArray::cast(heap_object);
}
const int increment = 2;
HeapObject heap_object;
maps_and_feedback->reserve(array.length() / increment);
for (int i = 0; i < array.length(); i += increment) {
DCHECK(array.Get(i)->IsWeakOrCleared());
if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) {
MaybeObject handler = array.Get(i + 1);
if (!handler->IsCleared()) {
Handle<Map> map(Map::cast(heap_object), isolate);
if (try_update_deprecated &&
!Map::TryUpdate(isolate, map).ToHandle(&map)) {
continue;
}
maps_and_feedback->push_back(
MapAndHandler(map, handle(handler, isolate)));
found++;
}
}
}
return found;
} else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
MaybeObject handler = GetFeedbackExtra();
if (!handler->IsCleared()) {
Handle<Map> map = handle(Map::cast(heap_object), isolate);
if (try_update_deprecated &&
!Map::TryUpdate(isolate, map).ToHandle(&map)) {
return 0;
}
maps_and_feedback->push_back(
MapAndHandler(map, handle(handler, isolate)));
return 1;
}
}
return 0;
return found;
}
int FeedbackNexus::ExtractMapsAndFeedback(
std::vector<MapAndFeedback>* maps_and_feedback,
bool try_update_deprecated) const {
DCHECK(IsLoadICKind(kind()) ||
IsStoreICKind(kind()) | IsKeyedLoadICKind(kind()) ||
IsKeyedStoreICKind(kind()) || IsStoreOwnICKind(kind()) ||
IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()) ||
IsStoreDataPropertyInLiteralKind(kind()));
int num_maps =
ExtractMapsAndFeedbackImpl(maps_and_feedback, try_update_deprecated);
#ifdef DEBUG
for (auto const& entry : *maps_and_feedback) {
DCHECK(IC::IsHandler(*entry.second) ||
IsStoreDataPropertyInLiteralKind(kind()));
std::vector<MapAndFeedback>* maps_and_feedback) const {
DisallowHeapAllocation no_gc;
Isolate* isolate = GetIsolate();
int found = 0;
for (FeedbackIterator it(this); !it.done(); it.Advance()) {
Handle<Map> map = handle(it.map(), isolate);
MaybeObject maybe_handler = it.handler();
if (!maybe_handler->IsCleared()) {
DCHECK(IC::IsHandler(maybe_handler) ||
IsStoreDataPropertyInLiteralKind(kind()));
MaybeObjectHandle handler = handle(maybe_handler, isolate);
maps_and_feedback->push_back(MapAndHandler(map, handler));
found++;
}
}
#endif
return num_maps;
return found;
}
int FeedbackNexus::ExtractMapsAndHandlers(
std::vector<MapAndHandler>* maps_and_handlers,
bool try_update_deprecated) const {
DCHECK(IsLoadICKind(kind()) ||
IsStoreICKind(kind()) | IsKeyedLoadICKind(kind()) ||
IsKeyedStoreICKind(kind()) || IsStoreOwnICKind(kind()) ||
IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
int num_maps =
ExtractMapsAndFeedbackImpl(maps_and_handlers, try_update_deprecated);
#ifdef DEBUG
for (auto const& entry : *maps_and_handlers) {
DCHECK(IC::IsHandler(*entry.second));
DCHECK(!IsStoreDataPropertyInLiteralKind(kind()));
DisallowHeapAllocation no_gc;
Isolate* isolate = GetIsolate();
int found = 0;
for (FeedbackIterator it(this); !it.done(); it.Advance()) {
Handle<Map> map = handle(it.map(), isolate);
MaybeObject maybe_handler = it.handler();
if (!maybe_handler->IsCleared()) {
DCHECK(IC::IsHandler(maybe_handler));
MaybeObjectHandle handler = handle(maybe_handler, isolate);
if (try_update_deprecated &&
!Map::TryUpdate(isolate, map).ToHandle(&map)) {
continue;
}
maps_and_handlers->push_back(MapAndHandler(map, handler));
found++;
}
}
#endif
return num_maps;
return found;
}
MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
IsKeyedHasICKind(kind()));
DCHECK(!IsStoreInArrayLiteralICKind(kind()));
MaybeObject feedback = GetFeedback();
Isolate* isolate = GetIsolate();
bool is_named_feedback = IsPropertyNameFeedback(feedback);
HeapObject heap_object;
if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
heap_object.IsWeakFixedArray()) ||
is_named_feedback) {
WeakFixedArray array;
if (is_named_feedback) {
array =
WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
} else {
array = WeakFixedArray::cast(heap_object);
}
const int increment = 2;
HeapObject heap_object;
for (int i = 0; i < array.length(); i += increment) {
DCHECK(array.Get(i)->IsWeakOrCleared());
if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) {
Map array_map = Map::cast(heap_object);
if (array_map == *map && !array.Get(i + increment - 1)->IsCleared()) {
MaybeObject handler = array.Get(i + increment - 1);
DCHECK(IC::IsHandler(handler));
return handle(handler, isolate);
}
}
}
} else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
Map cell_map = Map::cast(heap_object);
if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) {
MaybeObject handler = GetFeedbackExtra();
DCHECK(IC::IsHandler(handler));
return handle(handler, isolate);
for (FeedbackIterator it(this); !it.done(); it.Advance()) {
if (it.map() == *map && !it.handler()->IsCleared()) {
return handle(it.handler(), GetIsolate());
}
}
return MaybeObjectHandle();
}
@ -1492,5 +1379,78 @@ void FeedbackNexus::ResetTypeProfile() {
SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
}
FeedbackIterator::FeedbackIterator(const FeedbackNexus* nexus)
: done_(false), index_(-1), state_(kOther) {
DCHECK(IsLoadICKind(nexus->kind()) ||
IsStoreICKind(nexus->kind()) | IsKeyedLoadICKind(nexus->kind()) ||
IsKeyedStoreICKind(nexus->kind()) || IsStoreOwnICKind(nexus->kind()) ||
IsStoreDataPropertyInLiteralKind(nexus->kind()) ||
IsStoreInArrayLiteralICKind(nexus->kind()) ||
IsKeyedHasICKind(nexus->kind()));
DisallowHeapAllocation no_gc;
Isolate* isolate = nexus->GetIsolate();
MaybeObject feedback = nexus->GetFeedback();
bool is_named_feedback = IsPropertyNameFeedback(feedback);
HeapObject heap_object;
if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
heap_object.IsWeakFixedArray()) ||
is_named_feedback) {
index_ = 0;
state_ = kPolymorphic;
heap_object = feedback->GetHeapObjectAssumeStrong();
if (is_named_feedback) {
polymorphic_feedback_ =
handle(WeakFixedArray::cast(
nexus->GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
isolate);
} else {
polymorphic_feedback_ =
handle(WeakFixedArray::cast(heap_object), isolate);
}
AdvancePolymorphic();
} else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
state_ = kMonomorphic;
MaybeObject handler = nexus->GetFeedbackExtra();
map_ = Map::cast(heap_object);
handler_ = handler;
} else {
done_ = true;
}
}
void FeedbackIterator::Advance() {
CHECK(!done_);
if (state_ == kMonomorphic) {
done_ = true;
return;
}
CHECK_EQ(state_, kPolymorphic);
AdvancePolymorphic();
}
void FeedbackIterator::AdvancePolymorphic() {
CHECK(!done_);
CHECK_EQ(state_, kPolymorphic);
int length = polymorphic_feedback_->length();
HeapObject heap_object;
while (index_ < length) {
if (polymorphic_feedback_->Get(index_)->GetHeapObjectIfWeak(&heap_object)) {
MaybeObject handler = polymorphic_feedback_->Get(index_ + kHandlerOffset);
map_ = Map::cast(heap_object);
handler_ = handler;
index_ += kEntrySize;
return;
}
index_ += kEntrySize;
}
CHECK_EQ(index_, length);
done_ = true;
}
} // namespace internal
} // namespace v8

View File

@ -13,6 +13,7 @@
#include "src/common/globals.h"
#include "src/objects/elements-kind.h"
#include "src/objects/map.h"
#include "src/objects/maybe-object.h"
#include "src/objects/name.h"
#include "src/objects/type-hints.h"
#include "src/zone/zone-containers.h"
@ -667,8 +668,8 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
// vector. The returned feedback need not be always a handler. It could be a
// name in the case of StoreDataInPropertyLiteral. This is used by TurboFan to
// get all the feedback stored in the vector.
int ExtractMapsAndFeedback(std::vector<MapAndFeedback>* maps_and_feedback,
bool try_update_deprecated = false) const;
int ExtractMapsAndFeedback(
std::vector<MapAndFeedback>* maps_and_feedback) const;
bool IsCleared() const {
InlineCacheState state = ic_state();
@ -778,9 +779,28 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
FeedbackVector vector_;
FeedbackSlot slot_;
FeedbackSlotKind kind_;
};
int ExtractMapsAndFeedbackImpl(std::vector<MapAndFeedback>* maps_and_feedback,
bool try_update_deprecated = false) const;
class V8_EXPORT_PRIVATE FeedbackIterator final {
public:
explicit FeedbackIterator(const FeedbackNexus* nexus);
void Advance();
bool done() { return done_; }
Map map() { return map_; }
MaybeObject handler() { return handler_; }
private:
void AdvancePolymorphic();
enum State { kMonomorphic, kPolymorphic, kOther };
static constexpr int kEntrySize = 2;
static constexpr int kHandlerOffset = 1;
Handle<WeakFixedArray> polymorphic_feedback_;
Map map_;
MaybeObject handler_;
bool done_;
int index_;
State state_;
};
inline BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback);