Commit 4ef29b1a authored by ulan's avatar ulan Committed by Commit bot

Refactor dependent code.

This simplifies the layout of dependent code array and optimizes it for sparse dependency groups.

BUG=chromium:554488
LOG=NO

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

Cr-Commit-Position: refs/heads/master@{#32170}
parent 71962e8c
......@@ -441,8 +441,7 @@ void LChunk::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) const {
}
}
for (int i = 0; i < maps.length(); i++) {
if (maps.at(i)->dependent_code()->number_of_entries(
DependentCode::kWeakCodeGroup) == 0) {
if (maps.at(i)->dependent_code()->IsEmpty(DependentCode::kWeakCodeGroup)) {
isolate()->heap()->AddRetainedMap(maps.at(i));
}
Map::AddDependentCode(maps.at(i), DependentCode::kWeakCodeGroup, code);
......
......@@ -351,8 +351,7 @@ void Map::VerifyOmittedMapChecks() {
if (!is_stable() ||
is_deprecated() ||
is_dictionary_map()) {
CHECK_EQ(0, dependent_code()->number_of_entries(
DependentCode::kPrototypeCheckGroup));
CHECK(dependent_code()->IsEmpty(DependentCode::kPrototypeCheckGroup));
}
}
......
......@@ -4873,14 +4873,38 @@ bool Map::CanOmitMapChecks() {
}
int DependentCode::number_of_entries(DependencyGroup group) {
if (length() == 0) return 0;
return Smi::cast(get(group))->value();
DependentCode* DependentCode::next_link() {
return DependentCode::cast(get(kNextLinkIndex));
}
void DependentCode::set_number_of_entries(DependencyGroup group, int value) {
set(group, Smi::FromInt(value));
void DependentCode::set_next_link(DependentCode* next) {
set(kNextLinkIndex, next);
}
int DependentCode::flags() { return Smi::cast(get(kFlagsIndex))->value(); }
void DependentCode::set_flags(int flags) {
set(kFlagsIndex, Smi::FromInt(flags));
}
int DependentCode::count() { return CountField::decode(flags()); }
void DependentCode::set_count(int value) {
set_flags(CountField::update(flags(), value));
}
DependentCode::DependencyGroup DependentCode::group() {
return static_cast<DependencyGroup>(GroupField::decode(flags()));
}
void DependentCode::set_group(DependentCode::DependencyGroup group) {
set_flags(GroupField::update(flags(), static_cast<int>(group)));
}
......@@ -4904,16 +4928,6 @@ void DependentCode::copy(int from, int to) {
}
void DependentCode::ExtendGroup(DependencyGroup group) {
GroupStartIndexes starts(this);
for (int g = kGroupCount - 1; g > group; g--) {
if (starts.at(g) < starts.at(g + 1)) {
copy(starts.at(g), starts.at(g + 1));
}
}
}
void Code::set_flags(Code::Flags flags) {
STATIC_ASSERT(Code::NUMBER_OF_KINDS <= KindField::kMax + 1);
WRITE_INT_FIELD(this, kFlagsOffset, flags);
......
......@@ -13984,20 +13984,6 @@ void Map::AddDependentCode(Handle<Map> map,
}
DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
Recompute(entries);
}
void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
start_indexes_[0] = 0;
for (int g = 1; g <= kGroupCount; g++) {
int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
start_indexes_[g] = start_indexes_[g - 1] + count;
}
}
Handle<DependentCode> DependentCode::InsertCompilationDependencies(
Handle<DependentCode> entries, DependencyGroup group,
Handle<Foreign> info) {
......@@ -14015,44 +14001,54 @@ Handle<DependentCode> DependentCode::InsertWeakCode(
Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
DependencyGroup group,
Handle<Object> object) {
GroupStartIndexes starts(*entries);
int start = starts.at(group);
int end = starts.at(group + 1);
int number_of_entries = starts.number_of_entries();
if (entries->length() == 0 || entries->group() > group) {
// There is no such group.
return DependentCode::New(group, object, entries);
}
if (entries->group() < group) {
// The group comes later in the list.
Handle<DependentCode> old_next(entries->next_link());
Handle<DependentCode> new_next = Insert(old_next, group, object);
if (!old_next.is_identical_to(new_next)) {
entries->set_next_link(*new_next);
}
return entries;
}
DCHECK_EQ(group, entries->group());
int count = entries->count();
// Check for existing entry to avoid duplicates.
for (int i = start; i < end; i++) {
for (int i = 0; i < count; i++) {
if (entries->object_at(i) == *object) return entries;
}
if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
if (entries->length() < kCodesStartIndex + count + 1) {
entries = EnsureSpace(entries);
// The number of codes can change after Compact and GC.
starts.Recompute(*entries);
start = starts.at(group);
end = starts.at(group + 1);
// Count could have changed, reload it.
count = entries->count();
}
entries->ExtendGroup(group);
entries->set_object_at(end, *object);
entries->set_number_of_entries(group, end + 1 - start);
entries->set_object_at(count, *object);
entries->set_count(count + 1);
return entries;
}
Handle<DependentCode> DependentCode::New(DependencyGroup group,
Handle<Object> object,
Handle<DependentCode> next) {
Isolate* isolate = next->GetIsolate();
Handle<DependentCode> result = Handle<DependentCode>::cast(
isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
result->set_next_link(*next);
result->set_flags(GroupField::encode(group) | CountField::encode(1));
result->set_object_at(0, *object);
return result;
}
Handle<DependentCode> DependentCode::EnsureSpace(
Handle<DependentCode> entries) {
Isolate* isolate = entries->GetIsolate();
if (entries->length() == 0) {
entries = Handle<DependentCode>::cast(
isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
for (int g = 0; g < kGroupCount; g++) {
entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
}
return entries;
}
if (entries->Compact()) return entries;
GroupStartIndexes starts(*entries);
int capacity =
kCodesStartIndex + DependentCode::Grow(starts.number_of_entries());
Isolate* isolate = entries->GetIsolate();
int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
int grow_by = capacity - entries->length();
return Handle<DependentCode>::cast(
isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
......@@ -14060,46 +14056,47 @@ Handle<DependentCode> DependentCode::EnsureSpace(
bool DependentCode::Compact() {
GroupStartIndexes starts(this);
int n = 0;
for (int g = 0; g < kGroupCount; g++) {
int start = starts.at(g);
int end = starts.at(g + 1);
int count = 0;
DCHECK(start >= n);
for (int i = start; i < end; i++) {
int old_count = count();
int new_count = 0;
for (int i = 0; i < old_count; i++) {
Object* obj = object_at(i);
if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
if (i != n + count) {
copy(i, n + count);
}
count++;
if (i != new_count) {
copy(i, new_count);
}
new_count++;
}
if (count != end - start) {
set_number_of_entries(static_cast<DependencyGroup>(g), count);
}
n += count;
set_count(new_count);
for (int i = new_count; i < old_count; i++) {
clear_at(i);
}
return n < starts.number_of_entries();
return new_count < old_count;
}
void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
WeakCell* code_cell) {
if (this->length() == 0 || this->group() > group) {
// There is no such group.
return;
}
if (this->group() < group) {
// The group comes later in the list.
next_link()->UpdateToFinishedCode(group, info, code_cell);
return;
}
DCHECK_EQ(group, this->group());
DisallowHeapAllocation no_gc;
GroupStartIndexes starts(this);
int start = starts.at(group);
int end = starts.at(group + 1);
for (int i = start; i < end; i++) {
int count = this->count();
for (int i = 0; i < count; i++) {
if (object_at(i) == info) {
set_object_at(i, code_cell);
break;
}
}
#ifdef DEBUG
for (int i = start; i < end; i++) {
for (int i = 0; i < count; i++) {
DCHECK(object_at(i) != info);
}
#endif
......@@ -14108,34 +14105,36 @@ void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
void DependentCode::RemoveCompilationDependencies(
DependentCode::DependencyGroup group, Foreign* info) {
if (this->length() == 0 || this->group() > group) {
// There is no such group.
return;
}
if (this->group() < group) {
// The group comes later in the list.
next_link()->RemoveCompilationDependencies(group, info);
return;
}
DCHECK_EQ(group, this->group());
DisallowHeapAllocation no_allocation;
GroupStartIndexes starts(this);
int start = starts.at(group);
int end = starts.at(group + 1);
int old_count = count();
// Find compilation info wrapper.
int info_pos = -1;
for (int i = start; i < end; i++) {
for (int i = 0; i < old_count; i++) {
if (object_at(i) == info) {
info_pos = i;
break;
}
}
if (info_pos == -1) return; // Not found.
int gap = info_pos;
// Use the last of each group to fill the gap in the previous group.
for (int i = group; i < kGroupCount; i++) {
int last_of_group = starts.at(i + 1) - 1;
DCHECK(last_of_group >= gap);
if (last_of_group == gap) continue;
copy(last_of_group, gap);
gap = last_of_group;
}
DCHECK(gap == starts.number_of_entries() - 1);
clear_at(gap); // Clear last gap.
set_number_of_entries(group, end - start - 1);
// Use the last code to fill the gap.
if (info_pos < old_count - 1) {
copy(old_count - 1, info_pos);
}
clear_at(old_count - 1);
set_count(old_count - 1);
#ifdef DEBUG
for (int i = start; i < end - 1; i++) {
for (int i = 0; i < old_count - 1; i++) {
DCHECK(object_at(i) != info);
}
#endif
......@@ -14143,30 +14142,55 @@ void DependentCode::RemoveCompilationDependencies(
bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
GroupStartIndexes starts(this);
int start = starts.at(group);
int end = starts.at(group + 1);
for (int i = start; i < end; i++) {
if (this->length() == 0 || this->group() > group) {
// There is no such group.
return false;
}
if (this->group() < group) {
// The group comes later in the list.
return next_link()->Contains(group, code_cell);
}
DCHECK_EQ(group, this->group());
int count = this->count();
for (int i = 0; i < count; i++) {
if (object_at(i) == code_cell) return true;
}
return false;
}
bool DependentCode::IsEmpty(DependencyGroup group) {
if (this->length() == 0 || this->group() > group) {
// There is no such group.
return true;
}
if (this->group() < group) {
// The group comes later in the list.
return next_link()->IsEmpty(group);
}
DCHECK_EQ(group, this->group());
return count() == 0;
}
bool DependentCode::MarkCodeForDeoptimization(
Isolate* isolate,
DependentCode::DependencyGroup group) {
if (this->length() == 0 || this->group() > group) {
// There is no such group.
return false;
}
if (this->group() < group) {
// The group comes later in the list.
return next_link()->MarkCodeForDeoptimization(isolate, group);
}
DCHECK_EQ(group, this->group());
DisallowHeapAllocation no_allocation_scope;
DependentCode::GroupStartIndexes starts(this);
int start = starts.at(group);
int end = starts.at(group + 1);
int code_entries = starts.number_of_entries();
if (start == end) return false;
// Mark all the code that needs to be deoptimized.
bool marked = false;
bool invalidate_embedded_objects = group == kWeakCodeGroup;
for (int i = start; i < end; i++) {
int count = this->count();
for (int i = 0; i < count; i++) {
Object* obj = object_at(i);
if (obj->IsWeakCell()) {
WeakCell* cell = WeakCell::cast(obj);
......@@ -14187,16 +14211,10 @@ bool DependentCode::MarkCodeForDeoptimization(
info->Abort();
}
}
// Compact the array by moving all subsequent groups to fill in the new holes.
for (int src = end, dst = start; src < code_entries; src++, dst++) {
copy(src, dst);
}
// Now the holes are at the end of the array, zap them for heap-verifier.
int removed = end - start;
for (int i = code_entries - removed; i < code_entries; i++) {
for (int i = 0; i < count; i++) {
clear_at(i);
}
set_number_of_entries(group, 0);
set_count(0);
return marked;
}
......
......@@ -5343,24 +5343,24 @@ class Code: public HeapObject {
};
// This class describes the layout of dependent codes array of a map. The
// array is partitioned into several groups of dependent codes. Each group
// contains codes with the same dependency on the map. The array has the
// following layout for n dependency groups:
// Dependent code is a singly linked list of fixed arrays. Each array contains
// code objects in weak cells for one dependent group. The suffix of the array
// can be filled with the undefined value if the number of codes is less than
// the length of the array.
//
// +----+----+-----+----+---------+----------+-----+---------+-----------+
// | C1 | C2 | ... | Cn | group 1 | group 2 | ... | group n | undefined |
// +----+----+-----+----+---------+----------+-----+---------+-----------+
// +------+-----------------+--------+--------+-----+--------+-----------+-----+
// | next | count & group 1 | code 1 | code 2 | ... | code n | undefined | ... |
// +------+-----------------+--------+--------+-----+--------+-----------+-----+
// |
// V
// +------+-----------------+--------+--------+-----+--------+-----------+-----+
// | next | count & group 2 | code 1 | code 2 | ... | code m | undefined | ... |
// +------+-----------------+--------+--------+-----+--------+-----------+-----+
// |
// V
// empty_fixed_array()
//
// The first n elements are Smis, each of them specifies the number of codes
// in the corresponding group. The subsequent elements contain grouped code
// objects in weak cells. The suffix of the array can be filled with the
// undefined value if the number of codes is less than the length of the
// array. The order of the code objects within a group is not preserved.
//
// All code indexes used in the class are counted starting from the first
// code object of the first group. In other words, code index 0 corresponds
// to array index n = kCodesStartIndex.
// The list of fixed arrays is ordered by dependency groups.
class DependentCode: public FixedArray {
public:
......@@ -5395,19 +5395,8 @@ class DependentCode: public FixedArray {
static const int kGroupCount = kAllocationSiteTransitionChangedGroup + 1;
// Array for holding the index of the first code object of each group.
// The last element stores the total number of code objects.
class GroupStartIndexes {
public:
explicit GroupStartIndexes(DependentCode* entries);
void Recompute(DependentCode* entries);
int at(int i) { return start_indexes_[i]; }
int number_of_entries() { return start_indexes_[kGroupCount]; }
private:
int start_indexes_[kGroupCount + 1];
};
bool Contains(DependencyGroup group, WeakCell* code_cell);
bool IsEmpty(DependencyGroup group);
static Handle<DependentCode> InsertCompilationDependencies(
Handle<DependentCode> entries, DependencyGroup group,
......@@ -5431,8 +5420,12 @@ class DependentCode: public FixedArray {
// The following low-level accessors should only be used by this class
// and the mark compact collector.
inline int number_of_entries(DependencyGroup group);
inline void set_number_of_entries(DependencyGroup group, int value);
inline DependentCode* next_link();
inline void set_next_link(DependentCode* next);
inline int count();
inline void set_count(int value);
inline DependencyGroup group();
inline void set_group(DependencyGroup group);
inline Object* object_at(int i);
inline void set_object_at(int i, Object* object);
inline void clear_at(int i);
......@@ -5446,10 +5439,9 @@ class DependentCode: public FixedArray {
static Handle<DependentCode> Insert(Handle<DependentCode> entries,
DependencyGroup group,
Handle<Object> object);
static Handle<DependentCode> New(DependencyGroup group, Handle<Object> object,
Handle<DependentCode> next);
static Handle<DependentCode> EnsureSpace(Handle<DependentCode> entries);
// Make a room at the end of the given group by moving out the first
// code objects of the subsequent groups.
inline void ExtendGroup(DependencyGroup group);
// Compact by removing cleared weak cells and return true if there was
// any cleared weak cell.
bool Compact();
......@@ -5457,7 +5449,14 @@ class DependentCode: public FixedArray {
if (number_of_entries < 5) return number_of_entries + 1;
return number_of_entries * 5 / 4;
}
static const int kCodesStartIndex = kGroupCount;
inline int flags();
inline void set_flags(int flags);
class GroupField : public BitField<int, 0, 3> {};
class CountField : public BitField<int, 3, 27> {};
STATIC_ASSERT(kGroupCount <= GroupField::kMax + 1);
static const int kNextLinkIndex = 0;
static const int kFlagsIndex = 1;
static const int kCodesStartIndex = 2;
};
......
......@@ -4723,12 +4723,12 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) {
CompileRun("%OptimizeFunctionOnNextCall(bar); bar();");
DependentCode::GroupStartIndexes starts(site->dependent_code());
CHECK_GE(starts.number_of_entries(), 1);
int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
CHECK(site->dependent_code()->object_at(index)->IsWeakCell());
CHECK_EQ(DependentCode::kAllocationSiteTransitionChangedGroup,
site->dependent_code()->group());
CHECK_EQ(1, site->dependent_code()->count());
CHECK(site->dependent_code()->object_at(0)->IsWeakCell());
Code* function_bar = Code::cast(
WeakCell::cast(site->dependent_code()->object_at(index))->value());
WeakCell::cast(site->dependent_code()->object_at(0))->value());
Handle<JSFunction> bar_handle = Handle<JSFunction>::cast(
v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
CcTest::global()
......@@ -4745,10 +4745,8 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) {
// The site still exists because of our global handle, but the code is no
// longer referred to by dependent_code().
DependentCode::GroupStartIndexes starts(site->dependent_code());
int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
CHECK(site->dependent_code()->object_at(index)->IsWeakCell() &&
WeakCell::cast(site->dependent_code()->object_at(index))->cleared());
CHECK(site->dependent_code()->object_at(0)->IsWeakCell() &&
WeakCell::cast(site->dependent_code()->object_at(0))->cleared());
}
......
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