A type vector with multiple IC types needs metadata.
authormvstanton@chromium.org <mvstanton@chromium.org>
Mon, 27 Oct 2014 16:34:28 +0000 (16:34 +0000)
committermvstanton@chromium.org <mvstanton@chromium.org>
Mon, 27 Oct 2014 16:34:39 +0000 (16:34 +0000)
This CL adds a bitset to describe the type of IC in each IC slot.
This is necessary for clearing ICs of different types.

With FLAG_vector_ics off (the current state), it's not required because
CALL_IC is the only type of IC in the vector.

R=ishell@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#24911}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24911 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/objects-inl.h
src/objects.h
src/type-feedback-vector-inl.h
src/type-feedback-vector.cc
src/type-feedback-vector.h
src/utils.h
test/cctest/test-feedback-vector.cc
test/cctest/test-utils.cc

index 33363238c4d28a056421c19d32e1e3935c13bb64..c00ecddb565afc5529e44a840c594e9dcf59dfa4 100644 (file)
@@ -2205,7 +2205,7 @@ void Object::VerifyApiCallResultType() {
 }
 
 
-Object* FixedArray::get(int index) {
+Object* FixedArray::get(int index) const {
   SLOW_DCHECK(index >= 0 && index < this->length());
   return READ_FIELD(this, kHeaderSize + index * kPointerSize);
 }
index 6ecbdf2d8b26717a0d7df679081b556293621de2..d70e02aebbdd842c3bd5b018eed02085fd50dc3a 100644 (file)
@@ -2415,7 +2415,7 @@ class IncrementalMarking;
 class FixedArray: public FixedArrayBase {
  public:
   // Setter and getter for elements.
-  inline Object* get(int index);
+  inline Object* get(int index) const;
   static inline Handle<Object> get(Handle<FixedArray> array, int index);
   // Setter that uses write barrier.
   inline void set(int index, Object* value);
index 477a5281d092880efc5e06b0af5fa9639403dbaa..612004ebee7e7dc9d4b7419f6563b92325e93da4 100644 (file)
 namespace v8 {
 namespace internal {
 
+int TypeFeedbackVector::ic_metadata_length() const {
+  return FLAG_vector_ics ? VectorICComputer::word_count(ICSlots()) : 0;
+}
+
+
 Handle<Object> TypeFeedbackVector::UninitializedSentinel(Isolate* isolate) {
   return isolate->factory()->uninitialized_symbol();
 }
index dcae7c72e657bacba67c4ee206fb28c57365098f..c0078c5001653cdf1eb41592b498b6f884af06c8 100644 (file)
 namespace v8 {
 namespace internal {
 
+// static
+TypeFeedbackVector::VectorICKind TypeFeedbackVector::FromCodeKind(
+    Code::Kind kind) {
+  switch (kind) {
+    case Code::CALL_IC:
+      return KindCallIC;
+    case Code::LOAD_IC:
+      return KindLoadIC;
+    case Code::KEYED_LOAD_IC:
+      return KindKeyedLoadIC;
+    default:
+      // Shouldn't get here.
+      UNREACHABLE();
+  }
+
+  return KindUnused;
+}
+
+
+// static
+Code::Kind TypeFeedbackVector::FromVectorICKind(VectorICKind kind) {
+  switch (kind) {
+    case KindCallIC:
+      return Code::CALL_IC;
+    case KindLoadIC:
+      return Code::LOAD_IC;
+    case KindKeyedLoadIC:
+      return Code::KEYED_LOAD_IC;
+    case KindUnused:
+      break;
+  }
+  // Sentinel for no information.
+  return Code::NUMBER_OF_KINDS;
+}
+
+
+Code::Kind TypeFeedbackVector::GetKind(FeedbackVectorICSlot slot) const {
+  if (!FLAG_vector_ics) {
+    // We only have CALL_ICs
+    return Code::CALL_IC;
+  }
+
+  int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
+  int data = Smi::cast(get(index))->value();
+  VectorICKind b = VectorICComputer::decode(data, slot.ToInt());
+  return FromVectorICKind(b);
+}
+
+
+void TypeFeedbackVector::SetKind(FeedbackVectorICSlot slot, Code::Kind kind) {
+  if (!FLAG_vector_ics) {
+    // Nothing to do if we only have CALL_ICs
+    return;
+  }
+
+  VectorICKind b = FromCodeKind(kind);
+  int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
+  int data = Smi::cast(get(index))->value();
+  int new_data = VectorICComputer::encode(data, slot.ToInt(), b);
+  set(index, Smi::FromInt(new_data));
+}
+
+
 // static
 Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(Isolate* isolate,
                                                         int slot_count,
                                                         int ic_slot_count) {
-  int length = slot_count + ic_slot_count + kReservedIndexCount;
+  int index_count =
+      FLAG_vector_ics ? VectorICComputer::word_count(ic_slot_count) : 0;
+  int length = slot_count + ic_slot_count + index_count + kReservedIndexCount;
   if (length == kReservedIndexCount) {
     return Handle<TypeFeedbackVector>::cast(
         isolate->factory()->empty_fixed_array());
@@ -24,17 +89,21 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(Isolate* isolate,
   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length, TENURED);
   if (ic_slot_count > 0) {
     array->set(kFirstICSlotIndex,
-               Smi::FromInt(slot_count + kReservedIndexCount));
+               Smi::FromInt(slot_count + index_count + kReservedIndexCount));
   } else {
     array->set(kFirstICSlotIndex, Smi::FromInt(length));
   }
   array->set(kWithTypesIndex, Smi::FromInt(0));
   array->set(kGenericCountIndex, Smi::FromInt(0));
+  // Fill the indexes with zeros.
+  for (int i = 0; i < index_count; i++) {
+    array->set(kReservedIndexCount + i, Smi::FromInt(0));
+  }
 
   // Ensure we can skip the write barrier
   Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
   DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
-  for (int i = kReservedIndexCount; i < length; i++) {
+  for (int i = kReservedIndexCount + index_count; i < length; i++) {
     array->set(i, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
   }
   return Handle<TypeFeedbackVector>::cast(array);
index ddfa8dd85a915bcbefd18508db4f3b47aaf08ccc..61463b0394fc8a5ed631ab8d76430755f9def6cc 100644 (file)
@@ -18,7 +18,9 @@ namespace internal {
 // 0: first_ic_slot_index (== length() if no ic slots are present)
 // 1: ics_with_types
 // 2: ics_with_generic_info
-// 3: first feedback slot
+// 3: type information for ic slots, if any
+// ...
+// N: first feedback slot (N >= 3)
 // ...
 // [<first_ic_slot_index>: feedback slot]
 // ...to length() - 1
@@ -36,7 +38,7 @@ class TypeFeedbackVector : public FixedArray {
   static const int kWithTypesIndex = 1;
   static const int kGenericCountIndex = 2;
 
-  int first_ic_slot_index() {
+  int first_ic_slot_index() const {
     DCHECK(length() >= kReservedIndexCount);
     return Smi::cast(get(kFirstICSlotIndex))->value();
   }
@@ -66,53 +68,64 @@ class TypeFeedbackVector : public FixedArray {
     }
   }
 
-  int Slots() {
+  inline int ic_metadata_length() const;
+
+  int Slots() const {
     if (length() == 0) return 0;
-    return Max(0, first_ic_slot_index() - kReservedIndexCount);
+    return Max(
+        0, first_ic_slot_index() - ic_metadata_length() - kReservedIndexCount);
   }
 
-  int ICSlots() {
+  int ICSlots() const {
     if (length() == 0) return 0;
     return length() - first_ic_slot_index();
   }
 
   // Conversion from a slot or ic slot to an integer index to the underlying
   // array.
-  int GetIndex(FeedbackVectorSlot slot) {
-    return kReservedIndexCount + slot.ToInt();
+  int GetIndex(FeedbackVectorSlot slot) const {
+    return kReservedIndexCount + ic_metadata_length() + slot.ToInt();
   }
 
-  int GetIndex(FeedbackVectorICSlot slot) {
+  int GetIndex(FeedbackVectorICSlot slot) const {
     int first_ic_slot = first_ic_slot_index();
     DCHECK(slot.ToInt() < ICSlots());
     return first_ic_slot + slot.ToInt();
   }
 
-
   // Conversion from an integer index to either a slot or an ic slot. The caller
   // should know what kind she expects.
-  FeedbackVectorSlot ToSlot(int index) {
+  FeedbackVectorSlot ToSlot(int index) const {
     DCHECK(index >= kReservedIndexCount && index < first_ic_slot_index());
-    return FeedbackVectorSlot(index - kReservedIndexCount);
+    return FeedbackVectorSlot(index - ic_metadata_length() -
+                              kReservedIndexCount);
   }
 
-  FeedbackVectorICSlot ToICSlot(int index) {
+  FeedbackVectorICSlot ToICSlot(int index) const {
     DCHECK(index >= first_ic_slot_index() && index < length());
     return FeedbackVectorICSlot(index - first_ic_slot_index());
   }
 
-  Object* Get(FeedbackVectorSlot slot) { return get(GetIndex(slot)); }
+  Object* Get(FeedbackVectorSlot slot) const { return get(GetIndex(slot)); }
   void Set(FeedbackVectorSlot slot, Object* value,
            WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
     set(GetIndex(slot), value, mode);
   }
 
-  Object* Get(FeedbackVectorICSlot slot) { return get(GetIndex(slot)); }
+  Object* Get(FeedbackVectorICSlot slot) const { return get(GetIndex(slot)); }
   void Set(FeedbackVectorICSlot slot, Object* value,
            WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
     set(GetIndex(slot), value, mode);
   }
 
+  // IC slots need metadata to recognize the type of IC. Set a Kind for every
+  // slot. If GetKind() returns Code::NUMBER_OF_KINDS, then there is
+  // no kind associated with this slot. This may happen in the current design
+  // if a decision is made at compile time not to emit an IC that was planned
+  // for at parse time. This can be eliminated if we encode kind at parse
+  // time.
+  Code::Kind GetKind(FeedbackVectorICSlot slot) const;
+  void SetKind(FeedbackVectorICSlot slot, Code::Kind kind);
 
   static Handle<TypeFeedbackVector> Allocate(Isolate* isolate, int slot_count,
                                              int ic_slot_count);
@@ -145,6 +158,19 @@ class TypeFeedbackVector : public FixedArray {
   static inline Object* RawUninitializedSentinel(Heap* heap);
 
  private:
+  enum VectorICKind {
+    KindUnused = 0x0,
+    KindCallIC = 0x1,
+    KindLoadIC = 0x2,
+    KindKeyedLoadIC = 0x3
+  };
+
+  static const int kVectorICKindBits = 2;
+  static VectorICKind FromCodeKind(Code::Kind kind);
+  static Code::Kind FromVectorICKind(VectorICKind kind);
+  typedef BitSetComputer<VectorICKind, kVectorICKindBits, kSmiValueSize,
+                         uint32_t> VectorICComputer;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackVector);
 };
 }
index e2e10fd73d0866f69082cbca6279e58e805b61e0..dcefa44070308d1445ef0734f06cdc1cf2c1d8b2 100644 (file)
@@ -238,6 +238,46 @@ template<class T, int shift, int size>
 class BitField64 : public BitFieldBase<T, shift, size, uint64_t> { };
 
 
+// ----------------------------------------------------------------------------
+// BitSetComputer is a help template for encoding and decoding information for
+// a variable number of items in an array.
+//
+// To encode boolean data in a smi array you would use:
+// typedef BitSetComputer<bool, 1, kSmiValueSize, uint32_t> BoolComputer;
+//
+template <class T, int kBitsPerItem, int kBitsPerWord, class U>
+class BitSetComputer {
+ public:
+  static const int kItemsPerWord = kBitsPerWord / kBitsPerItem;
+  static const int kMask = (1 << kBitsPerItem) - 1;
+
+  // The number of array elements required to embed T information for each item.
+  static int word_count(int items) {
+    if (items == 0) return 0;
+    return (items - 1) / kItemsPerWord + 1;
+  }
+
+  // The array index to look at for item.
+  static int index(int base_index, int item) {
+    return base_index + item / kItemsPerWord;
+  }
+
+  // Extract T data for a given item from data.
+  static T decode(U data, int item) {
+    return static_cast<T>((data >> shift(item)) & kMask);
+  }
+
+  // Return the encoding for a store of value for item in previous.
+  static U encode(U previous, int item, T value) {
+    int shift_value = shift(item);
+    int set_bits = (static_cast<int>(value) << shift_value);
+    return (previous & ~(kMask << shift_value)) | set_bits;
+  }
+
+  static int shift(int item) { return (item % kItemsPerWord) * kBitsPerItem; }
+};
+
+
 // ----------------------------------------------------------------------------
 // Hash function.
 
index 517d19f535bc0c61260a57b65adcca401ed8d1b2..656e23b20035b54177db93b48737381191cb4199 100644 (file)
@@ -45,15 +45,73 @@ TEST(VectorStructure) {
   CHECK_EQ(3, vector->Slots());
   CHECK_EQ(5, vector->ICSlots());
 
+  int metadata_length = vector->ic_metadata_length();
+  if (!FLAG_vector_ics) {
+    CHECK_EQ(0, metadata_length);
+  } else {
+    CHECK(metadata_length > 0);
+  }
+
   int index = vector->GetIndex(FeedbackVectorSlot(0));
-  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount, index);
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
   CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
 
   index = vector->GetIndex(FeedbackVectorICSlot(0));
-  CHECK_EQ(index, TypeFeedbackVector::kReservedIndexCount + 3);
+  CHECK_EQ(index,
+           TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
   CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
 
-  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + 3 + 5, vector->length());
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
+           vector->length());
+}
+
+
+// IC slots need an encoding to recognize what is in there.
+TEST(VectorICMetadata) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  if (!FLAG_vector_ics) {
+    // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so
+    // there is no need for metadata to describe the slots.
+    return;
+  }
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<TypeFeedbackVector> vector =
+      factory->NewTypeFeedbackVector(10, 3 * 10);
+  CHECK_EQ(10, vector->Slots());
+  CHECK_EQ(3 * 10, vector->ICSlots());
+
+  // Set metadata.
+  for (int i = 0; i < 30; i++) {
+    Code::Kind kind;
+    if (i % 3 == 0)
+      kind = Code::CALL_IC;
+    else if (i % 3 == 1)
+      kind = Code::LOAD_IC;
+    else if (i % 3 == 2)
+      kind = Code::KEYED_LOAD_IC;
+    vector->SetKind(FeedbackVectorICSlot(i), kind);
+  }
+
+  // Meanwhile set some feedback values and type feedback values to
+  // verify the data structure remains intact.
+  vector->change_ic_with_type_info_count(100);
+  vector->change_ic_generic_count(3333);
+  vector->Set(FeedbackVectorSlot(0), *vector);
+
+  // Verify the metadata remains the same.
+  for (int i = 0; i < 30; i++) {
+    Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
+    if (i % 3 == 0) {
+      CHECK_EQ(Code::CALL_IC, kind);
+    } else if (i % 3 == 1) {
+      CHECK_EQ(Code::LOAD_IC, kind);
+    } else {
+      CHECK_EQ(Code::KEYED_LOAD_IC, kind);
+    }
+  }
 }
 
 
@@ -129,11 +187,14 @@ TEST(VectorICProfilerStatistics) {
   CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
   CHECK_EQ(0, feedback_vector->ic_generic_count());
 
-  CHECK(feedback_vector->Get(FeedbackVectorICSlot(0))->IsAllocationSite());
+  int ic_slot = FLAG_vector_ics ? 1 : 0;
+  CHECK(
+      feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
   feedback_vector = f->shared()->feedback_vector();
   CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
   CHECK_EQ(0, feedback_vector->ic_generic_count());
-  CHECK(feedback_vector->Get(FeedbackVectorICSlot(0))->IsAllocationSite());
+  CHECK(
+      feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
 }
 }
index 0c1e0412d3484db5d4d94a9c90732ae45e9ece29..8c5ad0e641d772cc11126c90a0ca4f76ea5e4fe3 100644 (file)
@@ -76,6 +76,46 @@ TEST(Utils1) {
 }
 
 
+TEST(BitSetComputer) {
+  typedef BitSetComputer<bool, 1, kSmiValueSize, uint32_t> BoolComputer;
+  CHECK_EQ(0, BoolComputer::word_count(0));
+  CHECK_EQ(1, BoolComputer::word_count(8));
+  CHECK_EQ(2, BoolComputer::word_count(50));
+  CHECK_EQ(0, BoolComputer::index(0, 8));
+  CHECK_EQ(100, BoolComputer::index(100, 8));
+  CHECK_EQ(1, BoolComputer::index(0, 40));
+  uint32_t data = 0;
+  data = BoolComputer::encode(data, 1, true);
+  data = BoolComputer::encode(data, 4, true);
+  CHECK_EQ(true, BoolComputer::decode(data, 1));
+  CHECK_EQ(true, BoolComputer::decode(data, 4));
+  CHECK_EQ(false, BoolComputer::decode(data, 0));
+  CHECK_EQ(false, BoolComputer::decode(data, 2));
+  CHECK_EQ(false, BoolComputer::decode(data, 3));
+
+  // Lets store 2 bits per item with 3000 items and verify the values are
+  // correct.
+  typedef BitSetComputer<unsigned char, 2, 8, unsigned char> TwoBits;
+  const int words = 750;
+  CHECK_EQ(words, TwoBits::word_count(3000));
+  const int offset = 10;
+  Vector<unsigned char> buffer = Vector<unsigned char>::New(offset + words);
+  memset(buffer.start(), 0, sizeof(unsigned char) * buffer.length());
+  for (int i = 0; i < words; i++) {
+    const int index = TwoBits::index(offset, i);
+    unsigned char data = buffer[index];
+    data = TwoBits::encode(data, i, i % 4);
+    buffer[index] = data;
+  }
+
+  for (int i = 0; i < words; i++) {
+    const int index = TwoBits::index(offset, i);
+    unsigned char data = buffer[index];
+    CHECK_EQ(i % 4, TwoBits::decode(data, i));
+  }
+}
+
+
 TEST(SNPrintF) {
   // Make sure that strings that are truncated because of too small
   // buffers are zero-terminated anyway.