}
-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);
}
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);
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();
}
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());
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);
// 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
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();
}
}
}
- 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);
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);
};
}
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.
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);
+ }
+ }
}
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());
}
}
}
+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.