Commit b74cfe4a authored by ishell's avatar ishell Committed by Commit bot

LayoutDescriptorHelper is now able to calculate the length of contiguous...

LayoutDescriptorHelper is now able to calculate the length of contiguous regions of tagged/non-tagged fields.
This functionality is now used by both object visitor and store buffer.

TEST=cctest/test-unboxed-doubles

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

Cr-Commit-Position: refs/heads/master@{#25816}
parent 286748c9
...@@ -1806,29 +1806,28 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, ...@@ -1806,29 +1806,28 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
promotion_queue()->remove(&target, &size); promotion_queue()->remove(&target, &size);
// Promoted object might be already partially visited // Promoted object might be already partially visited
// during old space pointer iteration. Thus we search specificly // during old space pointer iteration. Thus we search specifically
// for pointers to from semispace instead of looking for pointers // for pointers to from semispace instead of looking for pointers
// to new space. // to new space.
DCHECK(!target->IsMap()); DCHECK(!target->IsMap());
Address start_address = target->address(); Address obj_address = target->address();
Address end_address = start_address + size;
#if V8_DOUBLE_FIELDS_UNBOXING #if V8_DOUBLE_FIELDS_UNBOXING
InobjectPropertiesHelper helper(target->map()); LayoutDescriptorHelper helper(target->map());
bool has_only_tagged_fields = helper.all_fields_tagged(); bool has_only_tagged_fields = helper.all_fields_tagged();
if (!has_only_tagged_fields) { if (!has_only_tagged_fields) {
for (Address slot = start_address; slot < end_address; for (int offset = 0; offset < size;) {
slot += kPointerSize) { int end_of_region_offset;
if (helper.IsTagged(static_cast<int>(slot - start_address))) { if (helper.IsTagged(offset, size, &end_of_region_offset)) {
// TODO(ishell): call this once for contiguous region IterateAndMarkPointersToFromSpace(
// of tagged fields. obj_address + offset, obj_address + end_of_region_offset,
IterateAndMarkPointersToFromSpace(slot, slot + kPointerSize, &ScavengeObject);
&ScavengeObject);
} }
offset = end_of_region_offset;
} }
} else { } else {
#endif #endif
IterateAndMarkPointersToFromSpace(start_address, end_address, IterateAndMarkPointersToFromSpace(obj_address, obj_address + size,
&ScavengeObject); &ScavengeObject);
#if V8_DOUBLE_FIELDS_UNBOXING #if V8_DOUBLE_FIELDS_UNBOXING
} }
......
...@@ -2783,7 +2783,7 @@ void MarkCompactCollector::MigrateObject(HeapObject* dst, HeapObject* src, ...@@ -2783,7 +2783,7 @@ void MarkCompactCollector::MigrateObject(HeapObject* dst, HeapObject* src,
bool may_contain_raw_values = src->MayContainRawValues(); bool may_contain_raw_values = src->MayContainRawValues();
#if V8_DOUBLE_FIELDS_UNBOXING #if V8_DOUBLE_FIELDS_UNBOXING
InobjectPropertiesHelper helper(src->map()); LayoutDescriptorHelper helper(src->map());
bool has_only_tagged_fields = helper.all_fields_tagged(); bool has_only_tagged_fields = helper.all_fields_tagged();
#endif #endif
for (int remaining = size / kPointerSize; remaining > 0; remaining--) { for (int remaining = size / kPointerSize; remaining > 0; remaining--) {
......
...@@ -226,16 +226,14 @@ class BodyVisitorBase : public AllStatic { ...@@ -226,16 +226,14 @@ class BodyVisitorBase : public AllStatic {
DCHECK(IsAligned(start_offset, kPointerSize) && DCHECK(IsAligned(start_offset, kPointerSize) &&
IsAligned(end_offset, kPointerSize)); IsAligned(end_offset, kPointerSize));
InobjectPropertiesHelper helper(object->map()); LayoutDescriptorHelper helper(object->map());
DCHECK(!helper.all_fields_tagged()); DCHECK(!helper.all_fields_tagged());
for (int offset = start_offset; offset < end_offset;) {
for (int offset = start_offset; offset < end_offset; int end_of_region_offset;
offset += kPointerSize) { if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) {
// Visit tagged fields only. IterateRawPointers(heap, object, offset, end_of_region_offset);
if (helper.IsTagged(offset)) {
// TODO(ishell): call this once for contiguous region of tagged fields.
IterateRawPointers(heap, object, offset, offset + kPointerSize);
} }
offset = end_of_region_offset;
} }
} }
}; };
......
...@@ -512,24 +512,28 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback, ...@@ -512,24 +512,28 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback,
bool may_contain_raw_values = heap_object->MayContainRawValues(); bool may_contain_raw_values = heap_object->MayContainRawValues();
if (!may_contain_raw_values) { if (!may_contain_raw_values) {
Address obj_address = heap_object->address(); Address obj_address = heap_object->address();
Address start_address = obj_address + HeapObject::kHeaderSize; const int start_offset = HeapObject::kHeaderSize;
Address end_address = obj_address + heap_object->Size(); const int end_offset = heap_object->Size();
#if V8_DOUBLE_FIELDS_UNBOXING #if V8_DOUBLE_FIELDS_UNBOXING
InobjectPropertiesHelper helper(heap_object->map()); LayoutDescriptorHelper helper(heap_object->map());
bool has_only_tagged_fields = helper.all_fields_tagged(); bool has_only_tagged_fields = helper.all_fields_tagged();
if (!has_only_tagged_fields) { if (!has_only_tagged_fields) {
for (Address slot = start_address; slot < end_address; for (int offset = start_offset; offset < end_offset;) {
slot += kPointerSize) { int end_of_region_offset;
if (helper.IsTagged(static_cast<int>(slot - obj_address))) { if (helper.IsTagged(offset, end_offset,
// TODO(ishell): call this once for contiguous region &end_of_region_offset)) {
// of tagged fields. FindPointersToNewSpaceInRegion(
FindPointersToNewSpaceInRegion(slot, slot + kPointerSize, obj_address + offset,
slot_callback, clear_maps); obj_address + end_of_region_offset, slot_callback,
clear_maps);
} }
offset = end_of_region_offset;
} }
} else { } else {
#endif #endif
Address start_address = obj_address + start_offset;
Address end_address = obj_address + end_offset;
// Object has only tagged fields. // Object has only tagged fields.
FindPointersToNewSpaceInRegion(start_address, end_address, FindPointersToNewSpaceInRegion(start_address, end_address,
slot_callback, clear_maps); slot_callback, clear_maps);
......
...@@ -53,7 +53,7 @@ LayoutDescriptor* LayoutDescriptor::FastPointerLayout() { ...@@ -53,7 +53,7 @@ LayoutDescriptor* LayoutDescriptor::FastPointerLayout() {
bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index, bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index,
uint32_t* layout_mask) { int* layout_bit_index) {
if (static_cast<unsigned>(field_index) >= static_cast<unsigned>(capacity())) { if (static_cast<unsigned>(field_index) >= static_cast<unsigned>(capacity())) {
return false; return false;
} }
...@@ -62,20 +62,20 @@ bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index, ...@@ -62,20 +62,20 @@ bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index,
CHECK((!IsSmi() && (*layout_word_index < length())) || CHECK((!IsSmi() && (*layout_word_index < length())) ||
(IsSmi() && (*layout_word_index < 1))); (IsSmi() && (*layout_word_index < 1)));
int layout_bit_index = field_index % kNumberOfBits; *layout_bit_index = field_index % kNumberOfBits;
*layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
return true; return true;
} }
LayoutDescriptor* LayoutDescriptor::SetTagged(int field_index, bool tagged) { LayoutDescriptor* LayoutDescriptor::SetTagged(int field_index, bool tagged) {
int layout_word_index; int layout_word_index;
uint32_t layout_mask; int layout_bit_index;
if (!GetIndexes(field_index, &layout_word_index, &layout_mask)) { if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
CHECK(false); CHECK(false);
return this; return this;
} }
uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
if (IsSlowLayout()) { if (IsSlowLayout()) {
uint32_t value = get_scalar(layout_word_index); uint32_t value = get_scalar(layout_word_index);
...@@ -102,12 +102,13 @@ bool LayoutDescriptor::IsTagged(int field_index) { ...@@ -102,12 +102,13 @@ bool LayoutDescriptor::IsTagged(int field_index) {
if (IsFastPointerLayout()) return true; if (IsFastPointerLayout()) return true;
int layout_word_index; int layout_word_index;
uint32_t layout_mask; int layout_bit_index;
if (!GetIndexes(field_index, &layout_word_index, &layout_mask)) { if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
// All bits after Out of bounds queries // All bits after Out of bounds queries
return true; return true;
} }
uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
if (IsSlowLayout()) { if (IsSlowLayout()) {
uint32_t value = get_scalar(layout_word_index); uint32_t value = get_scalar(layout_word_index);
...@@ -155,7 +156,7 @@ LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) { ...@@ -155,7 +156,7 @@ LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) {
// InobjectPropertiesHelper is a helper class for querying whether inobject // InobjectPropertiesHelper is a helper class for querying whether inobject
// property at offset is Double or not. // property at offset is Double or not.
InobjectPropertiesHelper::InobjectPropertiesHelper(Map* map) LayoutDescriptorHelper::LayoutDescriptorHelper(Map* map)
: all_fields_tagged_(true), : all_fields_tagged_(true),
header_size_(0), header_size_(0),
layout_descriptor_(LayoutDescriptor::FastPointerLayout()) { layout_descriptor_(LayoutDescriptor::FastPointerLayout()) {
...@@ -175,7 +176,7 @@ InobjectPropertiesHelper::InobjectPropertiesHelper(Map* map) ...@@ -175,7 +176,7 @@ InobjectPropertiesHelper::InobjectPropertiesHelper(Map* map)
} }
bool InobjectPropertiesHelper::IsTagged(int offset_in_bytes) { bool LayoutDescriptorHelper::IsTagged(int offset_in_bytes) {
DCHECK(IsAligned(offset_in_bytes, kPointerSize)); DCHECK(IsAligned(offset_in_bytes, kPointerSize));
if (all_fields_tagged_) return true; if (all_fields_tagged_) return true;
// Object headers do not contain non-tagged fields. // Object headers do not contain non-tagged fields.
......
...@@ -6,8 +6,11 @@ ...@@ -6,8 +6,11 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/base/bits.h"
#include "src/layout-descriptor.h" #include "src/layout-descriptor.h"
using v8::base::bits::CountTrailingZeros32;
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -143,5 +146,111 @@ Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity( ...@@ -143,5 +146,111 @@ Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
return new_layout_descriptor; return new_layout_descriptor;
} }
} }
bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
int* out_sequence_length) {
DCHECK(max_sequence_length > 0);
if (IsFastPointerLayout()) {
*out_sequence_length = max_sequence_length;
return true;
}
int layout_word_index;
int layout_bit_index;
if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
// Out of bounds queries are considered tagged.
*out_sequence_length = max_sequence_length;
return true;
}
uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
uint32_t value = IsSlowLayout()
? get_scalar(layout_word_index)
: static_cast<uint32_t>(Smi::cast(this)->value());
bool is_tagged = (value & layout_mask) == 0;
if (!is_tagged) value = ~value; // Count set bits instead of cleared bits.
value = value & ~(layout_mask - 1); // Clear bits we are not interested in.
int sequence_length = CountTrailingZeros32(value) - layout_bit_index;
if (layout_bit_index + sequence_length == kNumberOfBits) {
// This is a contiguous sequence till the end of current word, proceed
// counting in the subsequent words.
if (IsSlowLayout()) {
int len = length();
++layout_word_index;
for (; layout_word_index < len; layout_word_index++) {
value = get_scalar(layout_word_index);
bool cur_is_tagged = (value & 1) == 0;
if (cur_is_tagged != is_tagged) break;
if (!is_tagged) value = ~value; // Count set bits instead.
int cur_sequence_length = CountTrailingZeros32(value);
sequence_length += cur_sequence_length;
if (sequence_length >= max_sequence_length) break;
if (cur_sequence_length != kNumberOfBits) break;
}
}
if (is_tagged && (field_index + sequence_length == capacity())) {
// The contiguous sequence of tagged fields lasts till the end of the
// layout descriptor which means that all the fields starting from
// field_index are tagged.
sequence_length = std::numeric_limits<int>::max();
}
}
*out_sequence_length = Min(sequence_length, max_sequence_length);
return is_tagged;
}
Handle<LayoutDescriptor> LayoutDescriptor::NewForTesting(Isolate* isolate,
int length) {
return New(isolate, length);
}
LayoutDescriptor* LayoutDescriptor::SetTaggedForTesting(int field_index,
bool tagged) {
return SetTagged(field_index, tagged);
}
bool LayoutDescriptorHelper::IsTagged(
int offset_in_bytes, int end_offset,
int* out_end_of_contiguous_region_offset) {
DCHECK(IsAligned(offset_in_bytes, kPointerSize));
DCHECK(IsAligned(end_offset, kPointerSize));
DCHECK(offset_in_bytes < end_offset);
if (all_fields_tagged_) {
*out_end_of_contiguous_region_offset = end_offset;
DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
return true;
}
int max_sequence_length = (end_offset - offset_in_bytes) / kPointerSize;
int field_index = Max(0, (offset_in_bytes - header_size_) / kPointerSize);
int sequence_length;
bool tagged = layout_descriptor_->IsTagged(field_index, max_sequence_length,
&sequence_length);
DCHECK(sequence_length > 0);
if (offset_in_bytes < header_size_) {
// Object headers do not contain non-tagged fields. Check if the contiguous
// region continues after the header.
if (tagged) {
// First field is tagged, calculate end offset from there.
*out_end_of_contiguous_region_offset =
header_size_ + sequence_length * kPointerSize;
} else {
*out_end_of_contiguous_region_offset = header_size_;
}
DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
return true;
}
*out_end_of_contiguous_region_offset =
offset_in_bytes + sequence_length * kPointerSize;
DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
return tagged;
}
} }
} // namespace v8::internal } // namespace v8::internal
...@@ -26,6 +26,14 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> { ...@@ -26,6 +26,14 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
public: public:
V8_INLINE bool IsTagged(int field_index); V8_INLINE bool IsTagged(int field_index);
// Queries the contiguous region of fields that are either tagged or not.
// Returns true if the given field is tagged or false otherwise and writes
// the length of the contiguous region to |out_sequence_length|.
// If the sequence is longer than |max_sequence_length| then
// |out_sequence_length| is set to |max_sequence_length|.
bool IsTagged(int field_index, int max_sequence_length,
int* out_sequence_length);
// Returns true if this is a layout of the object having only tagged fields. // Returns true if this is a layout of the object having only tagged fields.
V8_INLINE bool IsFastPointerLayout(); V8_INLINE bool IsFastPointerLayout();
V8_INLINE static bool IsFastPointerLayout(Object* layout_descriptor); V8_INLINE static bool IsFastPointerLayout(Object* layout_descriptor);
...@@ -76,10 +84,8 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> { ...@@ -76,10 +84,8 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
// Capacity of layout descriptors in bits. // Capacity of layout descriptors in bits.
V8_INLINE int capacity(); V8_INLINE int capacity();
V8_INLINE LayoutDescriptor* SetTaggedForTesting(int field_index, static Handle<LayoutDescriptor> NewForTesting(Isolate* isolate, int length);
bool tagged) { LayoutDescriptor* SetTaggedForTesting(int field_index, bool tagged);
return SetTagged(field_index, tagged);
}
private: private:
static const int kNumberOfBits = 32; static const int kNumberOfBits = 32;
...@@ -96,7 +102,7 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> { ...@@ -96,7 +102,7 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
// Returns false if requested field_index is out of bounds. // Returns false if requested field_index is out of bounds.
V8_INLINE bool GetIndexes(int field_index, int* layout_word_index, V8_INLINE bool GetIndexes(int field_index, int* layout_word_index,
uint32_t* layout_mask); int* layout_bit_index);
V8_INLINE MUST_USE_RESULT LayoutDescriptor* SetRawData(int field_index) { V8_INLINE MUST_USE_RESULT LayoutDescriptor* SetRawData(int field_index) {
return SetTagged(field_index, false); return SetTagged(field_index, false);
...@@ -107,15 +113,23 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> { ...@@ -107,15 +113,23 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
}; };
// InobjectPropertiesHelper is a helper class for querying layout descriptor // LayoutDescriptorHelper is a helper class for querying layout descriptor
// about whether the field at given offset is tagged or not. // about whether the field at given offset is tagged or not.
class InobjectPropertiesHelper { class LayoutDescriptorHelper {
public: public:
inline explicit InobjectPropertiesHelper(Map* map); inline explicit LayoutDescriptorHelper(Map* map);
bool all_fields_tagged() { return all_fields_tagged_; } bool all_fields_tagged() { return all_fields_tagged_; }
inline bool IsTagged(int offset_in_bytes); inline bool IsTagged(int offset_in_bytes);
// Queries the contiguous region of fields that are either tagged or not.
// Returns true if fields starting at |offset_in_bytes| are tagged or false
// otherwise and writes the offset of the end of the contiguous region to
// |out_end_of_contiguous_region_offset|. The |end_offset| value is the
// upper bound for |out_end_of_contiguous_region_offset|.
bool IsTagged(int offset_in_bytes, int end_offset,
int* out_end_of_contiguous_region_offset);
private: private:
bool all_fields_tagged_; bool all_fields_tagged_;
int header_size_; int header_size_;
......
...@@ -7421,7 +7421,7 @@ static inline void IterateBodyUsingLayoutDescriptor(HeapObject* object, ...@@ -7421,7 +7421,7 @@ static inline void IterateBodyUsingLayoutDescriptor(HeapObject* object,
DCHECK(IsAligned(start_offset, kPointerSize) && DCHECK(IsAligned(start_offset, kPointerSize) &&
IsAligned(end_offset, kPointerSize)); IsAligned(end_offset, kPointerSize));
InobjectPropertiesHelper helper(object->map()); LayoutDescriptorHelper helper(object->map());
DCHECK(!helper.all_fields_tagged()); DCHECK(!helper.all_fields_tagged());
for (int offset = start_offset; offset < end_offset; offset += kPointerSize) { for (int offset = start_offset; offset < end_offset; offset += kPointerSize) {
......
...@@ -31,6 +31,8 @@ static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) { ...@@ -31,6 +31,8 @@ static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
} }
} }
const int kNumberOfBits = 32;
enum TestPropertyKind { enum TestPropertyKind {
PROP_CONSTANT, PROP_CONSTANT,
...@@ -103,6 +105,14 @@ TEST(LayoutDescriptorBasicFast) { ...@@ -103,6 +105,14 @@ TEST(LayoutDescriptorBasicFast) {
CHECK_EQ(true, layout_desc->IsTagged(i)); CHECK_EQ(true, layout_desc->IsTagged(i));
} }
CHECK(layout_desc->IsFastPointerLayout()); CHECK(layout_desc->IsFastPointerLayout());
int sequence_length;
CHECK_EQ(true, layout_desc->IsTagged(0, std::numeric_limits<int>::max(),
&sequence_length));
CHECK_EQ(std::numeric_limits<int>::max(), sequence_length);
CHECK_EQ(true, layout_desc->IsTagged(0, 7, &sequence_length));
CHECK_EQ(7, sequence_length);
} }
...@@ -196,6 +206,239 @@ TEST(LayoutDescriptorBasicSlow) { ...@@ -196,6 +206,239 @@ TEST(LayoutDescriptorBasicSlow) {
} }
static void TestLayoutDescriptorQueries(int layout_descriptor_length,
int* bit_flip_positions,
int max_sequence_length) {
Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::NewForTesting(
CcTest::i_isolate(), layout_descriptor_length);
layout_descriptor_length = layout_descriptor->capacity();
LayoutDescriptor* layout_desc = *layout_descriptor;
{
// Fill in the layout descriptor.
int cur_bit_flip_index = 0;
bool tagged = true;
for (int i = 0; i < layout_descriptor_length; i++) {
if (i == bit_flip_positions[cur_bit_flip_index]) {
tagged = !tagged;
++cur_bit_flip_index;
CHECK(i < bit_flip_positions[cur_bit_flip_index]); // check test data
}
layout_desc = layout_desc->SetTaggedForTesting(i, tagged);
}
}
if (layout_desc->IsFastPointerLayout()) {
return;
}
{
// Check queries.
int cur_bit_flip_index = 0;
bool tagged = true;
for (int i = 0; i < layout_descriptor_length; i++) {
if (i == bit_flip_positions[cur_bit_flip_index]) {
tagged = !tagged;
++cur_bit_flip_index;
}
CHECK_EQ(tagged, layout_desc->IsTagged(i));
int next_bit_flip_position = bit_flip_positions[cur_bit_flip_index];
int expected_sequence_length;
if (next_bit_flip_position < layout_desc->capacity()) {
expected_sequence_length = next_bit_flip_position - i;
} else {
expected_sequence_length = tagged ? std::numeric_limits<int>::max()
: (layout_desc->capacity() - i);
}
expected_sequence_length =
Min(expected_sequence_length, max_sequence_length);
int sequence_length;
CHECK_EQ(tagged,
layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
CHECK(sequence_length > 0);
CHECK_EQ(expected_sequence_length, sequence_length);
}
int sequence_length;
CHECK_EQ(true,
layout_desc->IsTagged(layout_descriptor_length,
max_sequence_length, &sequence_length));
CHECK_EQ(max_sequence_length, sequence_length);
}
}
static void TestLayoutDescriptorQueriesFast(int max_sequence_length) {
{
LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
int sequence_length;
for (int i = 0; i < kNumberOfBits; i++) {
CHECK_EQ(true,
layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
CHECK(sequence_length > 0);
CHECK_EQ(max_sequence_length, sequence_length);
}
}
{
int bit_flip_positions[] = {1000};
TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[] = {0, 1000};
TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[kNumberOfBits + 1];
for (int i = 0; i <= kNumberOfBits; i++) {
bit_flip_positions[i] = i;
}
TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[] = {3, 7, 8, 10, 15, 21, 30, 1000};
TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[] = {0, 1, 2, 3, 5, 7, 9,
12, 15, 18, 22, 26, 29, 1000};
TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
max_sequence_length);
}
}
TEST(LayoutDescriptorQueriesFastLimited7) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
TestLayoutDescriptorQueriesFast(7);
}
TEST(LayoutDescriptorQueriesFastLimited13) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
TestLayoutDescriptorQueriesFast(13);
}
TEST(LayoutDescriptorQueriesFastUnlimited) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
TestLayoutDescriptorQueriesFast(std::numeric_limits<int>::max());
}
static void TestLayoutDescriptorQueriesSlow(int max_sequence_length) {
{
int bit_flip_positions[] = {10000};
TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[] = {0, 10000};
TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[kMaxNumberOfDescriptors + 1];
for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
bit_flip_positions[i] = i;
}
bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[] = {3, 7, 8, 10, 15, 21, 30,
37, 54, 80, 99, 383, 10000};
TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[] = {0, 10, 20, 30, 50, 70, 90,
120, 150, 180, 220, 260, 290, 10000};
TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[kMaxNumberOfDescriptors + 1];
int cur = 0;
for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
bit_flip_positions[i] = cur;
cur = (cur + 1) * 2;
}
CHECK(cur < 10000);
bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
max_sequence_length);
}
{
int bit_flip_positions[kMaxNumberOfDescriptors + 1];
int cur = 3;
for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
bit_flip_positions[i] = cur;
cur = (cur + 1) * 2;
}
CHECK(cur < 10000);
bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
max_sequence_length);
}
}
TEST(LayoutDescriptorQueriesSlowLimited7) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
TestLayoutDescriptorQueriesSlow(7);
}
TEST(LayoutDescriptorQueriesSlowLimited13) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
TestLayoutDescriptorQueriesSlow(13);
}
TEST(LayoutDescriptorQueriesSlowLimited42) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
TestLayoutDescriptorQueriesSlow(42);
}
TEST(LayoutDescriptorQueriesSlowUnlimited) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
TestLayoutDescriptorQueriesSlow(std::numeric_limits<int>::max());
}
TEST(LayoutDescriptorCreateNewFast) { TEST(LayoutDescriptorCreateNewFast) {
CcTest::InitializeVM(); CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
...@@ -708,6 +951,151 @@ TEST(DoScavenge) { ...@@ -708,6 +951,151 @@ TEST(DoScavenge) {
} }
static void TestLayoutDescriptorHelper(Isolate* isolate,
int inobject_properties,
Handle<DescriptorArray> descriptors,
int number_of_descriptors) {
Handle<Map> map = Map::Create(isolate, inobject_properties);
Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
map, descriptors, descriptors->number_of_descriptors());
map->InitializeDescriptors(*descriptors, *layout_descriptor);
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
LayoutDescriptorHelper helper(*map);
bool all_fields_tagged = true;
int instance_size = map->instance_size();
int end_offset = instance_size * 2;
int first_non_tagged_field_offset = end_offset;
for (int i = 0; i < number_of_descriptors; i++) {
PropertyDetails details = descriptors->GetDetails(i);
if (details.type() != FIELD) continue;
FieldIndex index = FieldIndex::ForDescriptor(*map, i);
if (!index.is_inobject()) continue;
all_fields_tagged &= !details.representation().IsDouble();
bool expected_tagged = !index.is_double();
if (!expected_tagged) {
first_non_tagged_field_offset =
Min(first_non_tagged_field_offset, index.offset());
}
int end_of_region_offset;
CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
CHECK_EQ(expected_tagged, helper.IsTagged(index.offset(), instance_size,
&end_of_region_offset));
CHECK(end_of_region_offset > 0);
CHECK(end_of_region_offset % kPointerSize == 0);
CHECK(end_of_region_offset <= instance_size);
for (int offset = index.offset(); offset < end_of_region_offset;
offset += kPointerSize) {
CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
}
if (end_of_region_offset < instance_size) {
CHECK_EQ(!expected_tagged, helper.IsTagged(end_of_region_offset));
} else {
CHECK_EQ(true, helper.IsTagged(end_of_region_offset));
}
}
for (int offset = 0; offset < JSObject::kHeaderSize; offset += kPointerSize) {
// Header queries
CHECK_EQ(true, helper.IsTagged(offset));
int end_of_region_offset;
CHECK_EQ(true, helper.IsTagged(offset, end_offset, &end_of_region_offset));
CHECK_EQ(first_non_tagged_field_offset, end_of_region_offset);
// Out of bounds queries
CHECK_EQ(true, helper.IsTagged(offset + instance_size));
}
CHECK_EQ(all_fields_tagged, helper.all_fields_tagged());
}
TEST(LayoutDescriptorHelperMixed) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
v8::HandleScope scope(CcTest::isolate());
Handle<LayoutDescriptor> layout_descriptor;
const int kPropsCount = kSmiValueSize * 3;
TestPropertyKind props[kPropsCount];
for (int i = 0; i < kPropsCount; i++) {
props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
}
Handle<DescriptorArray> descriptors =
CreateDescriptorArray(isolate, props, kPropsCount);
TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
kPropsCount);
TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
}
TEST(LayoutDescriptorHelperAllTagged) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
v8::HandleScope scope(CcTest::isolate());
Handle<LayoutDescriptor> layout_descriptor;
const int kPropsCount = kSmiValueSize * 3;
TestPropertyKind props[kPropsCount];
for (int i = 0; i < kPropsCount; i++) {
props[i] = PROP_TAGGED;
}
Handle<DescriptorArray> descriptors =
CreateDescriptorArray(isolate, props, kPropsCount);
TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
kPropsCount);
TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
}
TEST(LayoutDescriptorHelperAllDoubles) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
v8::HandleScope scope(CcTest::isolate());
Handle<LayoutDescriptor> layout_descriptor;
const int kPropsCount = kSmiValueSize * 3;
TestPropertyKind props[kPropsCount];
for (int i = 0; i < kPropsCount; i++) {
props[i] = PROP_DOUBLE;
}
Handle<DescriptorArray> descriptors =
CreateDescriptorArray(isolate, props, kPropsCount);
TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
kPropsCount);
TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
}
TEST(StoreBufferScanOnScavenge) { TEST(StoreBufferScanOnScavenge) {
CcTest::InitializeVM(); CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
......
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