Revision: 24911
Author:   [email protected]
Date:     Mon Oct 27 16:34:28 2014 UTC
Log:      A type vector with multiple IC types needs metadata.

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.

[email protected]

Review URL: https://codereview.chromium.org/679073002
https://code.google.com/p/v8/source/detail?r=24911

Modified:
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/type-feedback-vector-inl.h
 /branches/bleeding_edge/src/type-feedback-vector.cc
 /branches/bleeding_edge/src/type-feedback-vector.h
 /branches/bleeding_edge/src/utils.h
 /branches/bleeding_edge/test/cctest/test-feedback-vector.cc
 /branches/bleeding_edge/test/cctest/test-utils.cc

=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Mon Oct 27 11:57:58 2014 UTC
+++ /branches/bleeding_edge/src/objects-inl.h   Mon Oct 27 16:34:28 2014 UTC
@@ -2205,7 +2205,7 @@
 }


-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);
 }
=======================================
--- /branches/bleeding_edge/src/objects.h       Mon Oct 27 11:57:58 2014 UTC
+++ /branches/bleeding_edge/src/objects.h       Mon Oct 27 16:34:28 2014 UTC
@@ -2415,7 +2415,7 @@
 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);
=======================================
--- /branches/bleeding_edge/src/type-feedback-vector-inl.h Mon Oct 20 11:42:56 2014 UTC +++ /branches/bleeding_edge/src/type-feedback-vector-inl.h Mon Oct 27 16:34:28 2014 UTC
@@ -10,6 +10,11 @@
 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();
 }
=======================================
--- /branches/bleeding_edge/src/type-feedback-vector.cc Mon Oct 20 11:42:56 2014 UTC +++ /branches/bleeding_edge/src/type-feedback-vector.cc Mon Oct 27 16:34:28 2014 UTC
@@ -11,11 +11,76 @@
 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<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);
=======================================
--- /branches/bleeding_edge/src/type-feedback-vector.h Mon Oct 20 11:42:56 2014 UTC +++ /branches/bleeding_edge/src/type-feedback-vector.h Mon Oct 27 16:34:28 2014 UTC
@@ -18,7 +18,9 @@
 // 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 @@
   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 @@
     }
   }

-  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 @@
   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);
 };
 }
=======================================
--- /branches/bleeding_edge/src/utils.h Mon Oct 20 12:04:22 2014 UTC
+++ /branches/bleeding_edge/src/utils.h Mon Oct 27 16:34:28 2014 UTC
@@ -238,6 +238,46 @@
 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.

=======================================
--- /branches/bleeding_edge/test/cctest/test-feedback-vector.cc Mon Oct 20 17:32:06 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-feedback-vector.cc Mon Oct 27 16:34:28 2014 UTC
@@ -44,16 +44,74 @@
   vector = factory->NewTypeFeedbackVector(3, 5);
   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 @@
   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());
 }
 }
=======================================
--- /branches/bleeding_edge/test/cctest/test-utils.cc Mon Oct 6 08:53:48 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-utils.cc Mon Oct 27 16:34:28 2014 UTC
@@ -74,6 +74,46 @@
   CHECK_EQ(INT_MIN, FastD2IChecked(-1.0e100));
   CHECK_EQ(INT_MIN, FastD2IChecked(v8::base::OS::nan_value()));
 }
+
+
+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) {

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to