Commit 7a21cdaf authored by ulan's avatar ulan Committed by Commit bot

Optimize ClearNonLiveReferences: do not compact prototype transitions in GC.

BUG=chromium:554488
LOG=NO

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

Cr-Commit-Position: refs/heads/master@{#32272}
parent e8bfedab
......@@ -2261,10 +2261,7 @@ void MarkCompactCollector::ClearNonLiveReferences() {
Map* map = Map::cast(obj);
if (!map->CanTransition()) continue;
MarkBit map_mark = Marking::MarkBitFrom(map);
bool alive = Marking::IsBlackOrGrey(map_mark);
if (alive) {
ClearNonLivePrototypeTransitions(map);
} else {
if (Marking::IsWhite(map_mark)) {
ClearNonLiveMapTransitions(map);
}
}
......@@ -2304,39 +2301,6 @@ void MarkCompactCollector::MarkDependentCodeListForDeoptimization(
}
void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
FixedArray* prototype_transitions =
TransitionArray::GetPrototypeTransitions(map);
int number_of_transitions =
TransitionArray::NumberOfPrototypeTransitions(prototype_transitions);
const int header = TransitionArray::kProtoTransitionHeaderSize;
int new_number_of_transitions = 0;
for (int i = 0; i < number_of_transitions; i++) {
Object* cell = prototype_transitions->get(header + i);
if (!WeakCell::cast(cell)->cleared()) {
if (new_number_of_transitions != i) {
prototype_transitions->set(header + new_number_of_transitions, cell);
Object** slot = prototype_transitions->RawFieldOfElementAt(
header + new_number_of_transitions);
RecordSlot(prototype_transitions, slot, cell);
}
new_number_of_transitions++;
}
}
if (new_number_of_transitions != number_of_transitions) {
TransitionArray::SetNumberOfPrototypeTransitions(prototype_transitions,
new_number_of_transitions);
}
// Fill slots that became free with undefined value.
for (int i = new_number_of_transitions; i < number_of_transitions; i++) {
prototype_transitions->set_undefined(header + i);
}
}
void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map) {
Object* potential_parent = map->GetBackPointer();
if (!potential_parent->IsMap()) return;
......
......@@ -656,7 +656,6 @@ class MarkCompactCollector {
// Map transitions from a live map to a dead map must be killed.
// We replace them with a null descriptor, with the same key.
void ClearNonLiveReferences();
void ClearNonLivePrototypeTransitions(Map* map);
void ClearNonLiveMapTransitions(Map* map);
void ClearMapTransitions(Map* map, Map* dead_transition);
bool ClearMapBackPointer(Map* map);
......
......@@ -233,6 +233,61 @@ bool TransitionArray::CanHaveMoreTransitions(Handle<Map> map) {
}
// static
bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) {
const int header = kProtoTransitionHeaderSize;
int number_of_transitions = NumberOfPrototypeTransitions(array);
if (number_of_transitions == 0) {
// Empty array cannot be compacted.
return false;
}
int new_number_of_transitions = 0;
for (int i = 0; i < number_of_transitions; i++) {
Object* cell = array->get(header + i);
if (!WeakCell::cast(cell)->cleared()) {
if (new_number_of_transitions != i) {
array->set(header + new_number_of_transitions, cell);
}
new_number_of_transitions++;
}
}
// Fill slots that became free with undefined value.
for (int i = new_number_of_transitions; i < number_of_transitions; i++) {
array->set_undefined(header + i);
}
if (number_of_transitions != new_number_of_transitions) {
SetNumberOfPrototypeTransitions(array, new_number_of_transitions);
}
return new_number_of_transitions < number_of_transitions;
}
// static
Handle<FixedArray> TransitionArray::GrowPrototypeTransitionArray(
Handle<FixedArray> array, int new_capacity, Isolate* isolate) {
// Grow array by factor 2 up to MaxCachedPrototypeTransitions.
int capacity = array->length() - kProtoTransitionHeaderSize;
new_capacity = Min(kMaxCachedPrototypeTransitions, new_capacity);
DCHECK_GT(new_capacity, capacity);
int grow_by = new_capacity - capacity;
array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by);
if (capacity < 0) {
// There was no prototype transitions array before, so the size
// couldn't be copied. Initialize it explicitly.
SetNumberOfPrototypeTransitions(*array, 0);
}
return array;
}
// static
int TransitionArray::NumberOfPrototypeTransitionsForTest(Map* map) {
FixedArray* transitions = GetPrototypeTransitions(map);
CompactPrototypeTransitionArray(transitions);
return TransitionArray::NumberOfPrototypeTransitions(transitions);
}
// static
void TransitionArray::PutPrototypeTransition(Handle<Map> map,
Handle<Object> prototype,
......@@ -252,23 +307,16 @@ void TransitionArray::PutPrototypeTransition(Handle<Map> map,
int transitions = NumberOfPrototypeTransitions(*cache) + 1;
if (transitions > capacity) {
// Grow array by factor 2 up to MaxCachedPrototypeTransitions.
int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2);
if (new_capacity == capacity) return;
int grow_by = new_capacity - capacity;
Isolate* isolate = map->GetIsolate();
cache = isolate->factory()->CopyFixedArrayAndGrow(cache, grow_by);
if (capacity < 0) {
// There was no prototype transitions array before, so the size
// couldn't be copied. Initialize it explicitly.
SetNumberOfPrototypeTransitions(*cache, 0);
// Grow the array if compacting it doesn't free space.
if (!CompactPrototypeTransitionArray(*cache)) {
if (capacity == kMaxCachedPrototypeTransitions) return;
cache = GrowPrototypeTransitionArray(cache, 2 * transitions,
map->GetIsolate());
SetPrototypeTransitions(map, cache);
}
SetPrototypeTransitions(map, cache);
}
// Reload number of transitions as GC might shrink them.
// Reload number of transitions as they might have been compacted.
int last = NumberOfPrototypeTransitions(*cache);
int entry = header + last;
......@@ -387,25 +435,9 @@ void TransitionArray::ReplaceTransitions(Handle<Map> map,
}
static void ZapPrototypeTransitions(Object* raw_transitions) {
DCHECK(TransitionArray::IsFullTransitionArray(raw_transitions));
TransitionArray* transitions = TransitionArray::cast(raw_transitions);
if (!transitions->HasPrototypeTransitions()) return;
FixedArray* proto_transitions = transitions->GetPrototypeTransitions();
MemsetPointer(proto_transitions->data_start(),
proto_transitions->GetHeap()->the_hole_value(),
proto_transitions->length());
}
void TransitionArray::SetPrototypeTransitions(
Handle<Map> map, Handle<FixedArray> proto_transitions) {
EnsureHasFullTransitionArray(map);
if (Heap::ShouldZapGarbage()) {
Object* raw_transitions = map->raw_transitions();
DCHECK(raw_transitions != *proto_transitions);
ZapPrototypeTransitions(raw_transitions);
}
TransitionArray* transitions = TransitionArray::cast(map->raw_transitions());
transitions->SetPrototypeTransitions(*proto_transitions);
}
......@@ -444,8 +476,10 @@ void TransitionArray::TraverseTransitionTreeInternal(Map* map,
for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) {
int index = TransitionArray::kProtoTransitionHeaderSize + i;
WeakCell* cell = WeakCell::cast(proto_trans->get(index));
TraverseTransitionTreeInternal(Map::cast(cell->value()), callback,
data);
if (!cell->cleared()) {
TraverseTransitionTreeInternal(Map::cast(cell->value()), callback,
data);
}
}
}
for (int i = 0; i < transitions->number_of_transitions(); ++i) {
......
......@@ -113,6 +113,7 @@ class TransitionArray: public FixedArray {
Object* raw = proto_transitions->get(kProtoTransitionNumberOfEntriesOffset);
return Smi::cast(raw)->value();
}
static int NumberOfPrototypeTransitionsForTest(Map* map);
static void SetNumberOfPrototypeTransitions(FixedArray* proto_transitions,
int value);
......@@ -272,6 +273,11 @@ class TransitionArray: public FixedArray {
static void SetPrototypeTransitions(Handle<Map> map,
Handle<FixedArray> proto_transitions);
static bool CompactPrototypeTransitionArray(FixedArray* array);
static Handle<FixedArray> GrowPrototypeTransitionArray(
Handle<FixedArray> array, int new_capacity, Isolate* isolate);
// Compares two tuples <key, kind, attributes>, returns -1 if
// tuple1 is "less" than tuple2, 0 if tuple1 equal to tuple2 and 1 otherwise.
static inline int CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1,
......
......@@ -2620,12 +2620,6 @@ TEST(InstanceOfStubWriteBarrier) {
}
static int NumberOfProtoTransitions(Map* map) {
return TransitionArray::NumberOfPrototypeTransitions(
TransitionArray::GetPrototypeTransitions(map));
}
TEST(PrototypeTransitionClearing) {
if (FLAG_never_compact) return;
CcTest::InitializeVM();
......@@ -2639,7 +2633,8 @@ TEST(PrototypeTransitionClearing) {
v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(
CcTest::global()->Get(ctx, v8_str("base")).ToLocalChecked()));
int initialTransitions = NumberOfProtoTransitions(baseObject->map());
int initialTransitions =
TransitionArray::NumberOfPrototypeTransitionsForTest(baseObject->map());
CompileRun(
"var live = [];"
......@@ -2651,12 +2646,14 @@ TEST(PrototypeTransitionClearing) {
"}");
// Verify that only dead prototype transitions are cleared.
CHECK_EQ(initialTransitions + 10,
NumberOfProtoTransitions(baseObject->map()));
CHECK_EQ(
initialTransitions + 10,
TransitionArray::NumberOfPrototypeTransitionsForTest(baseObject->map()));
CcTest::heap()->CollectAllGarbage();
const int transitions = 10 - 3;
CHECK_EQ(initialTransitions + transitions,
NumberOfProtoTransitions(baseObject->map()));
CHECK_EQ(
initialTransitions + transitions,
TransitionArray::NumberOfPrototypeTransitionsForTest(baseObject->map()));
// Verify that prototype transitions array was compacted.
FixedArray* trans =
......
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