aboutsummaryrefslogtreecommitdiff
path: root/src/feedback-vector.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/feedback-vector.cc')
-rw-r--r--src/feedback-vector.cc1023
1 files changed, 1023 insertions, 0 deletions
diff --git a/src/feedback-vector.cc b/src/feedback-vector.cc
new file mode 100644
index 00000000..4003068e
--- /dev/null
+++ b/src/feedback-vector.cc
@@ -0,0 +1,1023 @@
+// 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.
+
+#include "src/feedback-vector.h"
+#include "src/code-stubs.h"
+#include "src/feedback-vector-inl.h"
+#include "src/ic/ic-inl.h"
+#include "src/ic/ic-state.h"
+#include "src/objects.h"
+
+namespace v8 {
+namespace internal {
+
+static bool IsPropertyNameFeedback(Object* feedback) {
+ if (feedback->IsString()) return true;
+ if (!feedback->IsSymbol()) return false;
+ Symbol* symbol = Symbol::cast(feedback);
+ Heap* heap = symbol->GetHeap();
+ return symbol != heap->uninitialized_symbol() &&
+ symbol != heap->premonomorphic_symbol() &&
+ symbol != heap->megamorphic_symbol();
+}
+
+std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
+ return os << FeedbackMetadata::Kind2String(kind);
+}
+
+FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
+ int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
+ int data = Smi::cast(get(index))->value();
+ return VectorICComputer::decode(data, slot.ToInt());
+}
+
+void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
+ int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
+ int data = Smi::cast(get(index))->value();
+ int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
+ set(index, Smi::FromInt(new_data));
+}
+
+template Handle<FeedbackMetadata> FeedbackMetadata::New(
+ Isolate* isolate, const StaticFeedbackVectorSpec* spec);
+template Handle<FeedbackMetadata> FeedbackMetadata::New(
+ Isolate* isolate, const FeedbackVectorSpec* spec);
+
+// static
+template <typename Spec>
+Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
+ const Spec* spec) {
+ Factory* factory = isolate->factory();
+
+ const int slot_count = spec->slots();
+ const int slot_kinds_length = VectorICComputer::word_count(slot_count);
+ const int length = slot_kinds_length + kReservedIndexCount;
+ if (length == kReservedIndexCount) {
+ return Handle<FeedbackMetadata>::cast(factory->empty_fixed_array());
+ }
+#ifdef DEBUG
+ for (int i = 0; i < slot_count;) {
+ FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
+ int entry_size = FeedbackMetadata::GetSlotSize(kind);
+ for (int j = 1; j < entry_size; j++) {
+ FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
+ DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
+ }
+ i += entry_size;
+ }
+#endif
+
+ Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
+ array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
+ // Fill the bit-vector part with zeros.
+ for (int i = 0; i < slot_kinds_length; i++) {
+ array->set(kReservedIndexCount + i, Smi::kZero);
+ }
+
+ Handle<FeedbackMetadata> metadata = Handle<FeedbackMetadata>::cast(array);
+
+ for (int i = 0; i < slot_count; i++) {
+ FeedbackSlot slot(i);
+ FeedbackSlotKind kind = spec->GetKind(slot);
+ metadata->SetKind(slot, kind);
+ }
+
+ // It's important that the FeedbackMetadata have a COW map, since it's
+ // pointed to by both a SharedFunctionInfo and indirectly by closures through
+ // the FeedbackVector. The serializer uses the COW map type to decide
+ // this object belongs in the startup snapshot and not the partial
+ // snapshot(s).
+ metadata->set_map(isolate->heap()->fixed_cow_array_map());
+
+ return metadata;
+}
+
+bool FeedbackMetadata::SpecDiffersFrom(
+ const FeedbackVectorSpec* other_spec) const {
+ if (other_spec->slots() != slot_count()) {
+ return true;
+ }
+
+ int slots = slot_count();
+ for (int i = 0; i < slots;) {
+ FeedbackSlot slot(i);
+ FeedbackSlotKind kind = GetKind(slot);
+ int entry_size = FeedbackMetadata::GetSlotSize(kind);
+
+ if (kind != other_spec->GetKind(slot)) {
+ return true;
+ }
+ i += entry_size;
+ }
+ return false;
+}
+
+const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
+ switch (kind) {
+ case FeedbackSlotKind::kInvalid:
+ return "INVALID";
+ case FeedbackSlotKind::kCall:
+ return "CALL_IC";
+ case FeedbackSlotKind::kLoadProperty:
+ return "LOAD_IC";
+ case FeedbackSlotKind::kLoadGlobalInsideTypeof:
+ return "LOAD_GLOBAL_INSIDE_TYPEOF_IC";
+ case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
+ return "LOAD_GLOBAL_NOT_INSIDE_TYPEOF_IC";
+ case FeedbackSlotKind::kLoadKeyed:
+ return "KEYED_LOAD_IC";
+ case FeedbackSlotKind::kStoreNamedSloppy:
+ return "STORE_SLOPPY_IC";
+ case FeedbackSlotKind::kStoreNamedStrict:
+ return "STORE_STRICT_IC";
+ case FeedbackSlotKind::kStoreOwnNamed:
+ return "STORE_OWN_IC";
+ case FeedbackSlotKind::kStoreKeyedSloppy:
+ return "KEYED_STORE_SLOPPY_IC";
+ case FeedbackSlotKind::kStoreKeyedStrict:
+ return "KEYED_STORE_STRICT_IC";
+ case FeedbackSlotKind::kBinaryOp:
+ return "INTERPRETER_BINARYOP_IC";
+ case FeedbackSlotKind::kCompareOp:
+ return "INTERPRETER_COMPARE_IC";
+ case FeedbackSlotKind::kToBoolean:
+ return "TO_BOOLEAN_IC";
+ case FeedbackSlotKind::kStoreDataPropertyInLiteral:
+ return "STORE_DATA_PROPERTY_IN_LITERAL_IC";
+ case FeedbackSlotKind::kCreateClosure:
+ return "kCreateClosure";
+ case FeedbackSlotKind::kLiteral:
+ return "LITERAL";
+ case FeedbackSlotKind::kGeneral:
+ return "STUB";
+ case FeedbackSlotKind::kKindsNumber:
+ break;
+ }
+ UNREACHABLE();
+ return "?";
+}
+
+FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
+ DCHECK(!is_empty());
+ return metadata()->GetKind(slot);
+}
+
+// static
+Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
+ Handle<SharedFunctionInfo> shared) {
+ Factory* factory = isolate->factory();
+
+ const int slot_count = shared->feedback_metadata()->slot_count();
+ const int length = slot_count + kReservedIndexCount;
+
+ Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
+ array->set_map_no_write_barrier(isolate->heap()->feedback_vector_map());
+ array->set(kSharedFunctionInfoIndex, *shared);
+ array->set(kInvocationCountIndex, Smi::kZero);
+
+ // Ensure we can skip the write barrier
+ Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
+ DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
+ Handle<Oddball> undefined_value = factory->undefined_value();
+ for (int i = 0; i < slot_count;) {
+ FeedbackSlot slot(i);
+ FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
+ int index = FeedbackVector::GetIndex(slot);
+ int entry_size = FeedbackMetadata::GetSlotSize(kind);
+
+ Object* extra_value = *uninitialized_sentinel;
+ switch (kind) {
+ case FeedbackSlotKind::kLoadGlobalInsideTypeof:
+ case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
+ array->set(index, isolate->heap()->empty_weak_cell(),
+ SKIP_WRITE_BARRIER);
+ break;
+ case FeedbackSlotKind::kCompareOp:
+ case FeedbackSlotKind::kBinaryOp:
+ case FeedbackSlotKind::kToBoolean:
+ array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
+ break;
+ case FeedbackSlotKind::kCreateClosure: {
+ Handle<Cell> cell = factory->NewNoClosuresCell(undefined_value);
+ array->set(index, *cell);
+ break;
+ }
+ case FeedbackSlotKind::kLiteral:
+ array->set(index, *undefined_value, SKIP_WRITE_BARRIER);
+ break;
+ case FeedbackSlotKind::kCall:
+ array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
+ extra_value = Smi::kZero;
+ break;
+ case FeedbackSlotKind::kLoadProperty:
+ case FeedbackSlotKind::kLoadKeyed:
+ case FeedbackSlotKind::kStoreNamedSloppy:
+ case FeedbackSlotKind::kStoreNamedStrict:
+ case FeedbackSlotKind::kStoreOwnNamed:
+ case FeedbackSlotKind::kStoreKeyedSloppy:
+ case FeedbackSlotKind::kStoreKeyedStrict:
+ case FeedbackSlotKind::kStoreDataPropertyInLiteral:
+ case FeedbackSlotKind::kGeneral:
+ array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
+ break;
+
+ case FeedbackSlotKind::kInvalid:
+ case FeedbackSlotKind::kKindsNumber:
+ UNREACHABLE();
+ array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
+ break;
+ }
+ for (int j = 1; j < entry_size; j++) {
+ array->set(index + j, extra_value, SKIP_WRITE_BARRIER);
+ }
+ i += entry_size;
+ }
+
+ Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(array);
+ if (isolate->IsCodeCoverageEnabled()) AddToCodeCoverageList(isolate, result);
+ return result;
+}
+
+// static
+Handle<FeedbackVector> FeedbackVector::Copy(Isolate* isolate,
+ Handle<FeedbackVector> vector) {
+ Handle<FeedbackVector> result;
+ result = Handle<FeedbackVector>::cast(
+ isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
+ if (isolate->IsCodeCoverageEnabled()) AddToCodeCoverageList(isolate, result);
+ return result;
+}
+
+// static
+void FeedbackVector::AddToCodeCoverageList(Isolate* isolate,
+ Handle<FeedbackVector> vector) {
+ DCHECK(isolate->IsCodeCoverageEnabled());
+ if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
+ Handle<ArrayList> list =
+ Handle<ArrayList>::cast(isolate->factory()->code_coverage_list());
+ list = ArrayList::Add(list, vector);
+ isolate->SetCodeCoverageList(*list);
+}
+
+void FeedbackVector::ClearSlots(JSFunction* host_function) {
+ Isolate* isolate = GetIsolate();
+
+ Object* uninitialized_sentinel =
+ FeedbackVector::RawUninitializedSentinel(isolate);
+ Oddball* undefined_value = isolate->heap()->undefined_value();
+
+ bool feedback_updated = false;
+ FeedbackMetadataIterator iter(metadata());
+ while (iter.HasNext()) {
+ FeedbackSlot slot = iter.Next();
+ FeedbackSlotKind kind = iter.kind();
+
+ Object* obj = Get(slot);
+ if (obj != uninitialized_sentinel) {
+ switch (kind) {
+ case FeedbackSlotKind::kCall: {
+ CallICNexus nexus(this, slot);
+ if (!nexus.IsCleared()) {
+ nexus.Clear();
+ feedback_updated = true;
+ }
+ break;
+ }
+ case FeedbackSlotKind::kLoadProperty: {
+ LoadICNexus nexus(this, slot);
+ if (!nexus.IsCleared()) {
+ nexus.Clear();
+ feedback_updated = true;
+ }
+ break;
+ }
+ case FeedbackSlotKind::kLoadGlobalInsideTypeof:
+ case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: {
+ LoadGlobalICNexus nexus(this, slot);
+ if (!nexus.IsCleared()) {
+ nexus.Clear();
+ feedback_updated = true;
+ }
+ break;
+ }
+ case FeedbackSlotKind::kLoadKeyed: {
+ KeyedLoadICNexus nexus(this, slot);
+ if (!nexus.IsCleared()) {
+ nexus.Clear();
+ feedback_updated = true;
+ }
+ break;
+ }
+ case FeedbackSlotKind::kStoreNamedSloppy:
+ case FeedbackSlotKind::kStoreNamedStrict:
+ case FeedbackSlotKind::kStoreOwnNamed: {
+ StoreICNexus nexus(this, slot);
+ if (!nexus.IsCleared()) {
+ nexus.Clear();
+ feedback_updated = true;
+ }
+ break;
+ }
+ case FeedbackSlotKind::kStoreKeyedSloppy:
+ case FeedbackSlotKind::kStoreKeyedStrict: {
+ KeyedStoreICNexus nexus(this, slot);
+ if (!nexus.IsCleared()) {
+ nexus.Clear();
+ feedback_updated = true;
+ }
+ break;
+ }
+ case FeedbackSlotKind::kBinaryOp:
+ case FeedbackSlotKind::kCompareOp: {
+ DCHECK(Get(slot)->IsSmi());
+ // don't clear these smi slots.
+ // Set(slot, Smi::kZero);
+ break;
+ }
+ case FeedbackSlotKind::kCreateClosure: {
+ break;
+ }
+ case FeedbackSlotKind::kGeneral: {
+ if (obj->IsHeapObject()) {
+ InstanceType instance_type =
+ HeapObject::cast(obj)->map()->instance_type();
+ // AllocationSites are exempt from clearing. They don't store Maps
+ // or Code pointers which can cause memory leaks if not cleared
+ // regularly.
+ if (instance_type != ALLOCATION_SITE_TYPE) {
+ Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
+ feedback_updated = true;
+ }
+ }
+ break;
+ }
+ case FeedbackSlotKind::kLiteral: {
+ Set(slot, undefined_value, SKIP_WRITE_BARRIER);
+ feedback_updated = true;
+ break;
+ }
+ case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
+ StoreDataPropertyInLiteralICNexus nexus(this, slot);
+ if (!nexus.IsCleared()) {
+ nexus.Clear();
+ feedback_updated = true;
+ }
+ break;
+ }
+ case FeedbackSlotKind::kToBoolean:
+ case FeedbackSlotKind::kInvalid:
+ case FeedbackSlotKind::kKindsNumber:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ if (feedback_updated) {
+ IC::OnFeedbackChanged(isolate, host_function);
+ }
+}
+
+Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
+ Isolate* isolate = GetIsolate();
+ Handle<Object> feedback = handle(GetFeedback(), isolate);
+ if (!feedback->IsFixedArray() ||
+ FixedArray::cast(*feedback)->length() != length) {
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
+ SetFeedback(*array);
+ return array;
+ }
+ return Handle<FixedArray>::cast(feedback);
+}
+
+Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
+ Isolate* isolate = GetIsolate();
+ Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
+ if (!feedback_extra->IsFixedArray() ||
+ FixedArray::cast(*feedback_extra)->length() != length) {
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
+ SetFeedbackExtra(*array);
+ return array;
+ }
+ return Handle<FixedArray>::cast(feedback_extra);
+}
+
+void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
+ MapHandleList* maps,
+ List<Handle<Object>>* handlers) {
+ int receiver_count = maps->length();
+ for (int current = 0; current < receiver_count; ++current) {
+ Handle<Map> map = maps->at(current);
+ Handle<WeakCell> cell = Map::WeakCellForMap(map);
+ array->set(current * 2, *cell);
+ array->set(current * 2 + 1, *handlers->at(current));
+ }
+}
+
+void FeedbackNexus::ConfigureUninitialized() {
+ SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+}
+
+void FeedbackNexus::ConfigurePremonomorphic() {
+ SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+}
+
+void FeedbackNexus::ConfigureMegamorphic() {
+ // Keyed ICs must use ConfigureMegamorphicKeyed.
+ DCHECK(!vector()->IsKeyedLoadIC(slot()));
+ DCHECK(!vector()->IsKeyedStoreIC(slot()));
+
+ Isolate* isolate = GetIsolate();
+ SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+}
+
+void KeyedLoadICNexus::ConfigureMegamorphicKeyed(IcCheckType property_type) {
+ Isolate* isolate = GetIsolate();
+ SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
+ SKIP_WRITE_BARRIER);
+}
+
+void KeyedStoreICNexus::ConfigureMegamorphicKeyed(IcCheckType property_type) {
+ Isolate* isolate = GetIsolate();
+ SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
+ SKIP_WRITE_BARRIER);
+}
+
+InlineCacheState LoadICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+
+ if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
+ return UNINITIALIZED;
+ } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
+ return MEGAMORPHIC;
+ } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
+ return PREMONOMORPHIC;
+ } else if (feedback->IsFixedArray()) {
+ // Determine state purely by our structure, don't check if the maps are
+ // cleared.
+ return POLYMORPHIC;
+ } else if (feedback->IsWeakCell()) {
+ // Don't check if the map is cleared.
+ return MONOMORPHIC;
+ }
+
+ return UNINITIALIZED;
+}
+
+InlineCacheState LoadGlobalICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+
+ Object* extra = GetFeedbackExtra();
+ if (!WeakCell::cast(feedback)->cleared() ||
+ extra != *FeedbackVector::UninitializedSentinel(isolate)) {
+ return MONOMORPHIC;
+ }
+ return UNINITIALIZED;
+}
+
+InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+
+ if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
+ return UNINITIALIZED;
+ } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
+ return PREMONOMORPHIC;
+ } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
+ return MEGAMORPHIC;
+ } else if (feedback->IsFixedArray()) {
+ // Determine state purely by our structure, don't check if the maps are
+ // cleared.
+ return POLYMORPHIC;
+ } else if (feedback->IsWeakCell()) {
+ // Don't check if the map is cleared.
+ return MONOMORPHIC;
+ } else if (feedback->IsName()) {
+ Object* extra = GetFeedbackExtra();
+ FixedArray* extra_array = FixedArray::cast(extra);
+ return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
+ }
+
+ return UNINITIALIZED;
+}
+
+InlineCacheState StoreICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+
+ if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
+ return UNINITIALIZED;
+ } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
+ return MEGAMORPHIC;
+ } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
+ return PREMONOMORPHIC;
+ } else if (feedback->IsFixedArray()) {
+ // Determine state purely by our structure, don't check if the maps are
+ // cleared.
+ return POLYMORPHIC;
+ } else if (feedback->IsWeakCell()) {
+ // Don't check if the map is cleared.
+ return MONOMORPHIC;
+ }
+
+ return UNINITIALIZED;
+}
+
+InlineCacheState KeyedStoreICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+
+ if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
+ return UNINITIALIZED;
+ } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
+ return PREMONOMORPHIC;
+ } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
+ return MEGAMORPHIC;
+ } else if (feedback->IsFixedArray()) {
+ // Determine state purely by our structure, don't check if the maps are
+ // cleared.
+ return POLYMORPHIC;
+ } else if (feedback->IsWeakCell()) {
+ // Don't check if the map is cleared.
+ return MONOMORPHIC;
+ } else if (feedback->IsName()) {
+ Object* extra = GetFeedbackExtra();
+ FixedArray* extra_array = FixedArray::cast(extra);
+ return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
+ }
+
+ return UNINITIALIZED;
+}
+
+InlineCacheState CallICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+ DCHECK(GetFeedbackExtra() ==
+ *FeedbackVector::UninitializedSentinel(isolate) ||
+ GetFeedbackExtra()->IsSmi());
+
+ if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
+ return GENERIC;
+ } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
+ return MONOMORPHIC;
+ }
+
+ CHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate));
+ return UNINITIALIZED;
+}
+
+int CallICNexus::ExtractCallCount() {
+ Object* call_count = GetFeedbackExtra();
+ CHECK(call_count->IsSmi());
+ int value = Smi::cast(call_count)->value();
+ return value;
+}
+
+float CallICNexus::ComputeCallFrequency() {
+ double const invocation_count = vector()->invocation_count();
+ double const call_count = ExtractCallCount();
+ return static_cast<float>(call_count / invocation_count);
+}
+
+void CallICNexus::ConfigureUninitialized() {
+ Isolate* isolate = GetIsolate();
+ SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
+}
+
+void CallICNexus::ConfigureMonomorphicArray() {
+ Object* feedback = GetFeedback();
+ if (!feedback->IsAllocationSite()) {
+ Handle<AllocationSite> new_site =
+ GetIsolate()->factory()->NewAllocationSite();
+ SetFeedback(*new_site);
+ }
+ SetFeedbackExtra(Smi::FromInt(1), SKIP_WRITE_BARRIER);
+}
+
+void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
+ Handle<WeakCell> new_cell = GetIsolate()->factory()->NewWeakCell(function);
+ SetFeedback(*new_cell);
+ SetFeedbackExtra(Smi::FromInt(1), SKIP_WRITE_BARRIER);
+}
+
+void CallICNexus::ConfigureMegamorphic() {
+ SetFeedback(*FeedbackVector::MegamorphicSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+ Smi* count = Smi::cast(GetFeedbackExtra());
+ int new_count = count->value() + 1;
+ SetFeedbackExtra(Smi::FromInt(new_count), SKIP_WRITE_BARRIER);
+}
+
+void CallICNexus::ConfigureMegamorphic(int call_count) {
+ SetFeedback(*FeedbackVector::MegamorphicSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(Smi::FromInt(call_count), SKIP_WRITE_BARRIER);
+}
+
+void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
+ Handle<Object> handler) {
+ Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+ SetFeedback(*cell);
+ SetFeedbackExtra(*handler);
+}
+
+void LoadGlobalICNexus::ConfigureUninitialized() {
+ Isolate* isolate = GetIsolate();
+ SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+}
+
+void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
+ Isolate* isolate = GetIsolate();
+ SetFeedback(*isolate->factory()->NewWeakCell(cell));
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+}
+
+void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Object> handler) {
+ SetFeedback(GetIsolate()->heap()->empty_weak_cell());
+ SetFeedbackExtra(*handler);
+}
+
+void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
+ Handle<Map> receiver_map,
+ Handle<Object> handler) {
+ Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+ if (name.is_null()) {
+ SetFeedback(*cell);
+ SetFeedbackExtra(*handler);
+ } else {
+ Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
+ SetFeedback(*name);
+ array->set(0, *cell);
+ array->set(1, *handler);
+ }
+}
+
+void StoreICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
+ Handle<Object> handler) {
+ Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+ SetFeedback(*cell);
+ SetFeedbackExtra(*handler);
+}
+
+void KeyedStoreICNexus::ConfigureMonomorphic(Handle<Name> name,
+ Handle<Map> receiver_map,
+ Handle<Object> handler) {
+ Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+ if (name.is_null()) {
+ SetFeedback(*cell);
+ SetFeedbackExtra(*handler);
+ } else {
+ Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
+ SetFeedback(*name);
+ array->set(0, *cell);
+ array->set(1, *handler);
+ }
+}
+
+void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
+ List<Handle<Object>>* handlers) {
+ Isolate* isolate = GetIsolate();
+ int receiver_count = maps->length();
+ Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
+ InstallHandlers(array, maps, handlers);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+}
+
+void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
+ MapHandleList* maps,
+ List<Handle<Object>>* handlers) {
+ int receiver_count = maps->length();
+ DCHECK(receiver_count > 1);
+ Handle<FixedArray> array;
+ if (name.is_null()) {
+ array = EnsureArrayOfSize(receiver_count * 2);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+ } else {
+ array = EnsureExtraArrayOfSize(receiver_count * 2);
+ SetFeedback(*name);
+ }
+
+ InstallHandlers(array, maps, handlers);
+}
+
+void StoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
+ List<Handle<Object>>* handlers) {
+ Isolate* isolate = GetIsolate();
+ int receiver_count = maps->length();
+ Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
+ InstallHandlers(array, maps, handlers);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
+}
+
+void KeyedStoreICNexus::ConfigurePolymorphic(Handle<Name> name,
+ MapHandleList* maps,
+ List<Handle<Object>>* handlers) {
+ int receiver_count = maps->length();
+ DCHECK(receiver_count > 1);
+ Handle<FixedArray> array;
+ if (name.is_null()) {
+ array = EnsureArrayOfSize(receiver_count * 2);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+ } else {
+ array = EnsureExtraArrayOfSize(receiver_count * 2);
+ SetFeedback(*name);
+ }
+
+ InstallHandlers(array, maps, handlers);
+}
+
+void KeyedStoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
+ MapHandleList* transitioned_maps,
+ List<Handle<Object>>* handlers) {
+ int receiver_count = maps->length();
+ DCHECK(receiver_count > 1);
+ Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 3);
+ SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+
+ Handle<Oddball> undefined_value = GetIsolate()->factory()->undefined_value();
+ for (int i = 0; i < receiver_count; ++i) {
+ Handle<Map> map = maps->at(i);
+ Handle<WeakCell> cell = Map::WeakCellForMap(map);
+ array->set(i * 3, *cell);
+ if (!transitioned_maps->at(i).is_null()) {
+ Handle<Map> transitioned_map = transitioned_maps->at(i);
+ cell = Map::WeakCellForMap(transitioned_map);
+ array->set((i * 3) + 1, *cell);
+ } else {
+ array->set((i * 3) + 1, *undefined_value);
+ }
+ array->set((i * 3) + 2, *handlers->at(i));
+ }
+}
+
+namespace {
+
+int GetStepSize(FixedArray* array, Isolate* isolate) {
+ // The array should be of the form
+ // [map, handler, map, handler, ...]
+ // or
+ // [map, map, handler, map, map, handler, ...]
+ // where "map" is either a WeakCell or |undefined|,
+ // and "handler" is either a Code object or a Smi.
+ DCHECK(array->length() >= 2);
+ Object* second = array->get(1);
+ if (second->IsWeakCell() || second->IsUndefined(isolate)) return 3;
+ DCHECK(IC::IsHandler(second));
+ return 2;
+}
+
+} // namespace
+
+int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+ bool is_named_feedback = IsPropertyNameFeedback(feedback);
+ if (feedback->IsFixedArray() || is_named_feedback) {
+ int found = 0;
+ if (is_named_feedback) {
+ feedback = GetFeedbackExtra();
+ }
+ FixedArray* array = FixedArray::cast(feedback);
+ int increment = GetStepSize(array, isolate);
+ for (int i = 0; i < array->length(); i += increment) {
+ DCHECK(array->get(i)->IsWeakCell());
+ WeakCell* cell = WeakCell::cast(array->get(i));
+ if (!cell->cleared()) {
+ Map* map = Map::cast(cell->value());
+ maps->Add(handle(map, isolate));
+ found++;
+ }
+ }
+ return found;
+ } else if (feedback->IsWeakCell()) {
+ WeakCell* cell = WeakCell::cast(feedback);
+ if (!cell->cleared()) {
+ Map* map = Map::cast(cell->value());
+ maps->Add(handle(map, isolate));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
+ Object* feedback = GetFeedback();
+ Isolate* isolate = GetIsolate();
+ bool is_named_feedback = IsPropertyNameFeedback(feedback);
+ if (feedback->IsFixedArray() || is_named_feedback) {
+ if (is_named_feedback) {
+ feedback = GetFeedbackExtra();
+ }
+ FixedArray* array = FixedArray::cast(feedback);
+ int increment = GetStepSize(array, isolate);
+ for (int i = 0; i < array->length(); i += increment) {
+ DCHECK(array->get(i)->IsWeakCell());
+ WeakCell* cell = WeakCell::cast(array->get(i));
+ if (!cell->cleared()) {
+ Map* array_map = Map::cast(cell->value());
+ if (array_map == *map) {
+ Object* code = array->get(i + increment - 1);
+ DCHECK(IC::IsHandler(code));
+ return handle(code, isolate);
+ }
+ }
+ }
+ } else if (feedback->IsWeakCell()) {
+ WeakCell* cell = WeakCell::cast(feedback);
+ if (!cell->cleared()) {
+ Map* cell_map = Map::cast(cell->value());
+ if (cell_map == *map) {
+ Object* code = GetFeedbackExtra();
+ DCHECK(IC::IsHandler(code));
+ return handle(code, isolate);
+ }
+ }
+ }
+
+ return MaybeHandle<Code>();
+}
+
+bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list,
+ int length) const {
+ Object* feedback = GetFeedback();
+ Isolate* isolate = GetIsolate();
+ int count = 0;
+ bool is_named_feedback = IsPropertyNameFeedback(feedback);
+ if (feedback->IsFixedArray() || is_named_feedback) {
+ if (is_named_feedback) {
+ feedback = GetFeedbackExtra();
+ }
+ FixedArray* array = FixedArray::cast(feedback);
+ int increment = GetStepSize(array, isolate);
+ for (int i = 0; i < array->length(); i += increment) {
+ DCHECK(array->get(i)->IsWeakCell());
+ WeakCell* cell = WeakCell::cast(array->get(i));
+ // Be sure to skip handlers whose maps have been cleared.
+ if (!cell->cleared()) {
+ Object* code = array->get(i + increment - 1);
+ DCHECK(IC::IsHandler(code));
+ code_list->Add(handle(code, isolate));
+ count++;
+ }
+ }
+ } else if (feedback->IsWeakCell()) {
+ WeakCell* cell = WeakCell::cast(feedback);
+ if (!cell->cleared()) {
+ Object* code = GetFeedbackExtra();
+ DCHECK(IC::IsHandler(code));
+ code_list->Add(handle(code, isolate));
+ count++;
+ }
+ }
+ return count == length;
+}
+
+Name* KeyedLoadICNexus::FindFirstName() const {
+ Object* feedback = GetFeedback();
+ if (IsPropertyNameFeedback(feedback)) {
+ return Name::cast(feedback);
+ }
+ return NULL;
+}
+
+Name* KeyedStoreICNexus::FindFirstName() const {
+ Object* feedback = GetFeedback();
+ if (IsPropertyNameFeedback(feedback)) {
+ return Name::cast(feedback);
+ }
+ return NULL;
+}
+
+KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
+ KeyedAccessStoreMode mode = STANDARD_STORE;
+ MapHandleList maps;
+ List<Handle<Object>> handlers;
+
+ if (GetKeyType() == PROPERTY) return mode;
+
+ ExtractMaps(&maps);
+ FindHandlers(&handlers, maps.length());
+ for (int i = 0; i < handlers.length(); i++) {
+ // The first handler that isn't the slow handler will have the bits we need.
+ Handle<Object> maybe_code_handler = handlers.at(i);
+ Handle<Code> handler;
+ if (maybe_code_handler->IsTuple2()) {
+ Handle<Tuple2> data_handler = Handle<Tuple2>::cast(maybe_code_handler);
+ handler = handle(Code::cast(data_handler->value2()));
+ } else {
+ handler = Handle<Code>::cast(maybe_code_handler);
+ }
+ CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
+ uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
+ CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
+ major_key == CodeStub::StoreFastElement ||
+ major_key == CodeStub::StoreSlowElement ||
+ major_key == CodeStub::ElementsTransitionAndStore ||
+ major_key == CodeStub::NoCache);
+ if (major_key != CodeStub::NoCache) {
+ mode = CommonStoreModeBits::decode(minor_key);
+ break;
+ }
+ }
+
+ return mode;
+}
+
+IcCheckType KeyedLoadICNexus::GetKeyType() const {
+ Object* feedback = GetFeedback();
+ if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
+ return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
+ }
+ return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
+}
+
+IcCheckType KeyedStoreICNexus::GetKeyType() const {
+ Object* feedback = GetFeedback();
+ if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
+ return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
+ }
+ return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
+}
+
+InlineCacheState BinaryOpICNexus::StateFromFeedback() const {
+ BinaryOperationHint hint = GetBinaryOperationFeedback();
+ if (hint == BinaryOperationHint::kNone) {
+ return UNINITIALIZED;
+ } else if (hint == BinaryOperationHint::kAny) {
+ return GENERIC;
+ }
+
+ return MONOMORPHIC;
+}
+
+InlineCacheState CompareICNexus::StateFromFeedback() const {
+ CompareOperationHint hint = GetCompareOperationFeedback();
+ if (hint == CompareOperationHint::kNone) {
+ return UNINITIALIZED;
+ } else if (hint == CompareOperationHint::kAny) {
+ return GENERIC;
+ }
+
+ return MONOMORPHIC;
+}
+
+BinaryOperationHint BinaryOpICNexus::GetBinaryOperationFeedback() const {
+ int feedback = Smi::cast(GetFeedback())->value();
+ return BinaryOperationHintFromFeedback(feedback);
+}
+
+CompareOperationHint CompareICNexus::GetCompareOperationFeedback() const {
+ int feedback = Smi::cast(GetFeedback())->value();
+ return CompareOperationHintFromFeedback(feedback);
+}
+
+InlineCacheState StoreDataPropertyInLiteralICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+
+ if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
+ return UNINITIALIZED;
+ } else if (feedback->IsWeakCell()) {
+ // Don't check if the map is cleared.
+ return MONOMORPHIC;
+ }
+
+ return MEGAMORPHIC;
+}
+
+void StoreDataPropertyInLiteralICNexus::ConfigureMonomorphic(
+ Handle<Name> name, Handle<Map> receiver_map) {
+ Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+
+ SetFeedback(*cell);
+ SetFeedbackExtra(*name);
+}
+
+} // namespace internal
+} // namespace v8