Commit 8bf73830 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[in-place weak refs] Replace WeakCells in TransitionArray::PrototypeTransitions.

BUG=v8:7308

Change-Id: Ib3926bfa22b8639d84374cf423d26d6362e3f46e
Reviewed-on: https://chromium-review.googlesource.com/1019141
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52694}
parent 2998a176
......@@ -1884,6 +1884,30 @@ Handle<FixedArray> Factory::CopyFixedArrayAndGrow(Handle<FixedArray> array,
return CopyArrayAndGrow(array, grow_by, pretenure);
}
Handle<WeakFixedArray> Factory::CopyWeakFixedArrayAndGrow(
Handle<WeakFixedArray> src, int grow_by, PretenureFlag pretenure) {
DCHECK(
!src->IsTransitionArray()); // Compacted by GC, this code doesn't work.
int old_len = src->length();
int new_len = old_len + grow_by;
DCHECK_GE(new_len, old_len);
HeapObject* obj = AllocateRawFixedArray(new_len, pretenure);
DCHECK_EQ(old_len, src->length());
obj->set_map_after_allocation(src->map(), SKIP_WRITE_BARRIER);
WeakFixedArray* result = WeakFixedArray::cast(obj);
result->set_length(new_len);
// Copy the content.
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = obj->GetWriteBarrierMode(no_gc);
for (int i = 0; i < old_len; i++) result->Set(i, src->Get(i), mode);
HeapObjectReference* undefined_reference =
HeapObjectReference::Strong(isolate()->heap()->undefined_value());
MemsetPointer(result->data_start() + old_len, undefined_reference, grow_by);
return Handle<WeakFixedArray>(result, isolate());
}
Handle<WeakArrayList> Factory::CopyWeakArrayListAndGrow(
Handle<WeakArrayList> src, int grow_by, PretenureFlag pretenure) {
int old_capacity = src->capacity();
......
......@@ -486,6 +486,10 @@ class V8_EXPORT_PRIVATE Factory {
Handle<FixedArray> array, int grow_by,
PretenureFlag pretenure = NOT_TENURED);
Handle<WeakFixedArray> CopyWeakFixedArrayAndGrow(
Handle<WeakFixedArray> array, int grow_by,
PretenureFlag pretenure = NOT_TENURED);
Handle<WeakArrayList> CopyWeakArrayListAndGrow(
Handle<WeakArrayList> array, int grow_by,
PretenureFlag pretenure = NOT_TENURED);
......
......@@ -237,6 +237,14 @@ void WeakFixedArray::Set(int index, MaybeObject* value) {
WEAK_WRITE_BARRIER(GetHeap(), this, offset, value);
}
void WeakFixedArray::Set(int index, MaybeObject* value, WriteBarrierMode mode) {
DCHECK_GE(index, 0);
DCHECK_LT(index, length());
int offset = OffsetOfElementAt(index);
RELAXED_WRITE_FIELD(this, offset, value);
CONDITIONAL_WEAK_WRITE_BARRIER(GetHeap(), this, offset, value, mode);
}
MaybeObject** WeakFixedArray::data_start() {
return HeapObject::RawMaybeWeakField(this, kHeaderSize);
}
......
......@@ -256,6 +256,9 @@ class WeakFixedArray : public HeapObject {
// Setter that uses write barrier.
inline void Set(int index, MaybeObject* value);
// Setter with explicit barrier mode.
inline void Set(int index, MaybeObject* value, WriteBarrierMode mode);
static constexpr int SizeFor(int length) {
return kHeaderSize + length * kPointerSize;
}
......
......@@ -28,12 +28,11 @@ bool TransitionArray::HasPrototypeTransitions() {
return Get(kPrototypeTransitionsIndex) != MaybeObject::FromSmi(Smi::kZero);
}
FixedArray* TransitionArray::GetPrototypeTransitions() {
WeakFixedArray* TransitionArray::GetPrototypeTransitions() {
DCHECK(HasPrototypeTransitions()); // Callers must check first.
Object* prototype_transitions =
Get(kPrototypeTransitionsIndex)->ToStrongHeapObject();
return FixedArray::cast(prototype_transitions);
return WeakFixedArray::cast(prototype_transitions);
}
HeapObjectReference** TransitionArray::GetKeySlot(int transition_number) {
......@@ -42,12 +41,19 @@ HeapObjectReference** TransitionArray::GetKeySlot(int transition_number) {
RawFieldOfElementAt(ToKeyIndex(transition_number)));
}
void TransitionArray::SetPrototypeTransitions(FixedArray* transitions) {
DCHECK(transitions->IsFixedArray());
void TransitionArray::SetPrototypeTransitions(WeakFixedArray* transitions) {
DCHECK(transitions->IsWeakFixedArray());
WeakFixedArray::Set(kPrototypeTransitionsIndex,
HeapObjectReference::Strong(transitions));
}
int TransitionArray::NumberOfPrototypeTransitions(
WeakFixedArray* proto_transitions) {
if (proto_transitions->length() == 0) return 0;
MaybeObject* raw =
proto_transitions->Get(kProtoTransitionNumberOfEntriesOffset);
return Smi::ToInt(raw->ToSmi());
}
Name* TransitionArray::GetKey(int transition_number) {
DCHECK(transition_number < number_of_transitions());
......
......@@ -309,7 +309,7 @@ bool TransitionsAccessor::IsMatchingMap(Map* target, Name* name,
}
// static
bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) {
bool TransitionArray::CompactPrototypeTransitionArray(WeakFixedArray* array) {
const int header = kProtoTransitionHeaderSize;
int number_of_transitions = NumberOfPrototypeTransitions(array);
if (number_of_transitions == 0) {
......@@ -318,17 +318,21 @@ bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) {
}
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()) {
MaybeObject* target = array->Get(header + i);
DCHECK(target->IsClearedWeakHeapObject() ||
(target->IsWeakHeapObject() && target->ToWeakHeapObject()->IsMap()));
if (!target->IsClearedWeakHeapObject()) {
if (new_number_of_transitions != i) {
array->set(header + new_number_of_transitions, cell);
array->Set(header + new_number_of_transitions, target);
}
new_number_of_transitions++;
}
}
// Fill slots that became free with undefined value.
MaybeObject* undefined = MaybeObject::FromObject(
*array->GetIsolate()->factory()->undefined_value());
for (int i = new_number_of_transitions; i < number_of_transitions; i++) {
array->set_undefined(header + i);
array->Set(header + i, undefined);
}
if (number_of_transitions != new_number_of_transitions) {
SetNumberOfPrototypeTransitions(array, new_number_of_transitions);
......@@ -338,14 +342,15 @@ bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) {
// static
Handle<FixedArray> TransitionArray::GrowPrototypeTransitionArray(
Handle<FixedArray> array, int new_capacity, Isolate* isolate) {
Handle<WeakFixedArray> TransitionArray::GrowPrototypeTransitionArray(
Handle<WeakFixedArray> 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, TENURED);
array =
isolate->factory()->CopyWeakFixedArrayAndGrow(array, grow_by, TENURED);
if (capacity < 0) {
// There was no prototype transitions array before, so the size
// couldn't be copied. Initialize it explicitly.
......@@ -364,7 +369,7 @@ void TransitionsAccessor::PutPrototypeTransition(Handle<Object> prototype,
const int header = TransitionArray::kProtoTransitionHeaderSize;
Handle<FixedArray> cache(GetPrototypeTransitions());
Handle<WeakFixedArray> cache(GetPrototypeTransitions());
int capacity = cache->length() - header;
int transitions = TransitionArray::NumberOfPrototypeTransitions(*cache) + 1;
......@@ -383,42 +388,43 @@ void TransitionsAccessor::PutPrototypeTransition(Handle<Object> prototype,
int last = TransitionArray::NumberOfPrototypeTransitions(*cache);
int entry = header + last;
Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map);
Reload(); // Reload after possible GC.
cache->set(entry, *target_cell);
cache->Set(entry, HeapObjectReference::Weak(*target_map));
TransitionArray::SetNumberOfPrototypeTransitions(*cache, last + 1);
}
Handle<Map> TransitionsAccessor::GetPrototypeTransition(
Handle<Object> prototype) {
DisallowHeapAllocation no_gc;
FixedArray* cache = GetPrototypeTransitions();
WeakFixedArray* cache = GetPrototypeTransitions();
int length = TransitionArray::NumberOfPrototypeTransitions(cache);
for (int i = 0; i < length; i++) {
WeakCell* target_cell = WeakCell::cast(
cache->get(TransitionArray::kProtoTransitionHeaderSize + i));
if (!target_cell->cleared() &&
Map::cast(target_cell->value())->prototype() == *prototype) {
return handle(Map::cast(target_cell->value()));
MaybeObject* target =
cache->Get(TransitionArray::kProtoTransitionHeaderSize + i);
DCHECK(target->IsClearedWeakHeapObject() || target->IsWeakHeapObject());
if (!target->IsClearedWeakHeapObject()) {
Map* map = Map::cast(target->ToWeakHeapObject());
if (map->prototype() == *prototype) {
return handle(map);
}
}
}
return Handle<Map>();
}
FixedArray* TransitionsAccessor::GetPrototypeTransitions() {
WeakFixedArray* TransitionsAccessor::GetPrototypeTransitions() {
if (encoding() != kFullTransitionArray ||
!transitions()->HasPrototypeTransitions()) {
return map_->GetHeap()->empty_fixed_array();
return map_->GetHeap()->empty_weak_fixed_array();
}
return transitions()->GetPrototypeTransitions();
}
// static
void TransitionArray::SetNumberOfPrototypeTransitions(
FixedArray* proto_transitions, int value) {
WeakFixedArray* proto_transitions, int value) {
DCHECK_NE(proto_transitions->length(), 0);
proto_transitions->set(kProtoTransitionNumberOfEntriesOffset,
Smi::FromInt(value));
proto_transitions->Set(kProtoTransitionNumberOfEntriesOffset,
MaybeObject::FromSmi(Smi::FromInt(value)));
}
int TransitionsAccessor::NumberOfTransitions() {
......@@ -461,7 +467,7 @@ void TransitionsAccessor::ReplaceTransitions(MaybeObject* new_transitions) {
}
void TransitionsAccessor::SetPrototypeTransitions(
Handle<FixedArray> proto_transitions) {
Handle<WeakFixedArray> proto_transitions) {
EnsureHasFullTransitionArray();
transitions()->SetPrototypeTransitions(*proto_transitions);
}
......@@ -502,13 +508,15 @@ void TransitionsAccessor::TraverseTransitionTreeInternal(
}
case kFullTransitionArray: {
if (transitions()->HasPrototypeTransitions()) {
FixedArray* proto_trans = transitions()->GetPrototypeTransitions();
WeakFixedArray* proto_trans = transitions()->GetPrototypeTransitions();
int length = TransitionArray::NumberOfPrototypeTransitions(proto_trans);
for (int i = 0; i < length; ++i) {
int index = TransitionArray::kProtoTransitionHeaderSize + i;
WeakCell* cell = WeakCell::cast(proto_trans->get(index));
if (cell->cleared()) continue;
TransitionsAccessor(Map::cast(cell->value()), no_gc)
MaybeObject* target = proto_trans->Get(index);
DCHECK(target->IsClearedWeakHeapObject() ||
target->IsWeakHeapObject());
if (target->IsClearedWeakHeapObject()) continue;
TransitionsAccessor(Map::cast(target->ToWeakHeapObject()), no_gc)
.TraverseTransitionTreeInternal(callback, data, no_gc);
}
}
......
......@@ -169,8 +169,8 @@ class TransitionsAccessor {
inline Map* GetTargetMapFromWeakRef();
void EnsureHasFullTransitionArray();
void SetPrototypeTransitions(Handle<FixedArray> proto_transitions);
FixedArray* GetPrototypeTransitions();
void SetPrototypeTransitions(Handle<WeakFixedArray> proto_transitions);
WeakFixedArray* GetPrototypeTransitions();
void TraverseTransitionTreeInternal(TraverseCallback callback, void* data,
DisallowHeapAllocation* no_gc);
......@@ -194,7 +194,7 @@ class TransitionsAccessor {
// should use TransitionsAccessors.
// TransitionArrays have the following format:
// [0] Link to next TransitionArray (for weak handling support) (strong ref)
// [1] Smi(0) or fixed array of prototype transitions (strong ref)
// [1] Smi(0) or WeakFixedArray of prototype transitions (strong ref)
// [2] Number of transitions (can be zero after trimming)
// [3] First transition key (strong ref)
// [4] First transition target (weak ref)
......@@ -204,7 +204,7 @@ class TransitionArray : public WeakFixedArray {
public:
DECL_CAST(TransitionArray)
inline FixedArray* GetPrototypeTransitions();
inline WeakFixedArray* GetPrototypeTransitions();
inline bool HasPrototypeTransitions();
// Accessors for fetching instance transition at transition number.
......@@ -281,14 +281,11 @@ class TransitionArray : public WeakFixedArray {
static const int kProtoTransitionHeaderSize = 1;
static const int kMaxCachedPrototypeTransitions = 256;
inline void SetPrototypeTransitions(FixedArray* prototype_transitions);
inline void SetPrototypeTransitions(WeakFixedArray* prototype_transitions);
static int NumberOfPrototypeTransitions(FixedArray* proto_transitions) {
if (proto_transitions->length() == 0) return 0;
Object* raw = proto_transitions->get(kProtoTransitionNumberOfEntriesOffset);
return Smi::ToInt(raw);
}
static void SetNumberOfPrototypeTransitions(FixedArray* proto_transitions,
static inline int NumberOfPrototypeTransitions(
WeakFixedArray* proto_transitions);
static void SetNumberOfPrototypeTransitions(WeakFixedArray* proto_transitions,
int value);
static const int kProtoTransitionNumberOfEntriesOffset = 0;
......@@ -316,10 +313,10 @@ class TransitionArray : public WeakFixedArray {
inline int number_of_transitions() const;
static bool CompactPrototypeTransitionArray(FixedArray* array);
static bool CompactPrototypeTransitionArray(WeakFixedArray* array);
static Handle<FixedArray> GrowPrototypeTransitionArray(
Handle<FixedArray> array, int new_capacity, Isolate* isolate);
static Handle<WeakFixedArray> GrowPrototypeTransitionArray(
Handle<WeakFixedArray> 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.
......
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