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.

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
parent 0755160e
......@@ -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);
}
......
......@@ -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);
......
......@@ -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();
}
......
......@@ -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<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);
......
......@@ -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);
};
}
......
......@@ -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.
......
......@@ -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());
}
}
......@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment