[in-place weak refs] Replace WeakCells in TransitionArray.
BUG=v8:7308 Change-Id: I1976cd7e542a0304f6e14744e634c62dd06a83f5 Reviewed-on: https://chromium-review.googlesource.com/1014090 Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#52672}
This commit is contained in:
parent
ddb2856f39
commit
7560b33eba
@ -1434,6 +1434,7 @@ TNode<Smi> CodeStubAssembler::LoadFastJSArrayLength(
|
||||
|
||||
TNode<Smi> CodeStubAssembler::LoadFixedArrayBaseLength(
|
||||
SloppyTNode<FixedArrayBase> array) {
|
||||
CSA_SLOW_ASSERT(this, IsNotWeakFixedArraySubclass(array));
|
||||
return CAST(LoadObjectField(array, FixedArrayBase::kLengthOffset));
|
||||
}
|
||||
|
||||
@ -1442,6 +1443,11 @@ TNode<IntPtrT> CodeStubAssembler::LoadAndUntagFixedArrayBaseLength(
|
||||
return LoadAndUntagObjectField(array, FixedArrayBase::kLengthOffset);
|
||||
}
|
||||
|
||||
TNode<IntPtrT> CodeStubAssembler::LoadAndUntagWeakFixedArrayLength(
|
||||
SloppyTNode<WeakFixedArray> array) {
|
||||
return LoadAndUntagObjectField(array, WeakFixedArray::kLengthOffset);
|
||||
}
|
||||
|
||||
TNode<Int32T> CodeStubAssembler::LoadMapBitField(SloppyTNode<Map> map) {
|
||||
CSA_SLOW_ASSERT(this, IsMap(map));
|
||||
return UncheckedCast<Int32T>(
|
||||
@ -1706,20 +1712,42 @@ void CodeStubAssembler::DispatchMaybeObject(Node* maybe_object, Label* if_smi,
|
||||
Goto(if_strong);
|
||||
}
|
||||
|
||||
TNode<Object> CodeStubAssembler::LoadFixedArrayElement(
|
||||
SloppyTNode<Object> object, Node* index_node, int additional_offset,
|
||||
ParameterMode parameter_mode, LoadSensitivity needs_poisoning) {
|
||||
Node* CodeStubAssembler::IsStrongHeapObject(Node* value) {
|
||||
return WordEqual(
|
||||
WordAnd(BitcastTaggedToWord(value), IntPtrConstant(kWeakHeapObjectMask)),
|
||||
IntPtrConstant(0));
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::ToStrongHeapObject(Node* value) {
|
||||
return BitcastWordToTagged(WordAnd(BitcastTaggedToWord(value),
|
||||
IntPtrConstant(~kWeakHeapObjectMask)));
|
||||
}
|
||||
|
||||
TNode<Object> CodeStubAssembler::LoadArrayElement(
|
||||
SloppyTNode<Object> object, int array_header_size, Node* index_node,
|
||||
int additional_offset, ParameterMode parameter_mode,
|
||||
LoadSensitivity needs_poisoning) {
|
||||
CSA_SLOW_ASSERT(this, IntPtrGreaterThanOrEqual(
|
||||
ParameterToIntPtr(index_node, parameter_mode),
|
||||
IntPtrConstant(0)));
|
||||
int32_t header_size =
|
||||
FixedArray::kHeaderSize + additional_offset - kHeapObjectTag;
|
||||
int32_t header_size = array_header_size + additional_offset - kHeapObjectTag;
|
||||
TNode<IntPtrT> offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS,
|
||||
parameter_mode, header_size);
|
||||
return UncheckedCast<Object>(
|
||||
Load(MachineType::AnyTagged(), object, offset, needs_poisoning));
|
||||
}
|
||||
|
||||
TNode<Object> CodeStubAssembler::LoadFixedArrayElement(
|
||||
SloppyTNode<Object> object, Node* index_node, int additional_offset,
|
||||
ParameterMode parameter_mode, LoadSensitivity needs_poisoning) {
|
||||
// This function is currently used for non-FixedArrays (e.g., PropertyArrays)
|
||||
// and thus the reasonable assert IsFixedArraySubclass(object) is
|
||||
// untrue. TODO(marja): Fix.
|
||||
CSA_SLOW_ASSERT(this, IsNotWeakFixedArraySubclass(object));
|
||||
return LoadArrayElement(object, FixedArray::kHeaderSize, index_node,
|
||||
additional_offset, parameter_mode, needs_poisoning);
|
||||
}
|
||||
|
||||
TNode<RawPtrT> CodeStubAssembler::LoadFixedTypedArrayBackingStore(
|
||||
TNode<FixedTypedArrayBase> typed_array) {
|
||||
// Backing store = external_pointer + base_pointer.
|
||||
@ -1941,13 +1969,11 @@ TNode<Object> CodeStubAssembler::LoadFeedbackVectorSlot(
|
||||
return UncheckedCast<Object>(Load(MachineType::AnyTagged(), object, offset));
|
||||
}
|
||||
|
||||
TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement(
|
||||
SloppyTNode<Object> object, Node* index_node, int additional_offset,
|
||||
ParameterMode parameter_mode) {
|
||||
CSA_SLOW_ASSERT(this, IsFixedArraySubclass(object));
|
||||
TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32ArrayElement(
|
||||
SloppyTNode<Object> object, int array_header_size, Node* index_node,
|
||||
int additional_offset, ParameterMode parameter_mode) {
|
||||
CSA_SLOW_ASSERT(this, MatchesParameterMode(index_node, parameter_mode));
|
||||
int32_t header_size =
|
||||
FixedArray::kHeaderSize + additional_offset - kHeapObjectTag;
|
||||
int32_t header_size = array_header_size + additional_offset - kHeapObjectTag;
|
||||
#if V8_TARGET_LITTLE_ENDIAN
|
||||
if (Is64()) {
|
||||
header_size += kPointerSize / 2;
|
||||
@ -1962,6 +1988,15 @@ TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement(
|
||||
}
|
||||
}
|
||||
|
||||
TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement(
|
||||
SloppyTNode<Object> object, Node* index_node, int additional_offset,
|
||||
ParameterMode parameter_mode) {
|
||||
CSA_SLOW_ASSERT(this, IsFixedArraySubclass(object));
|
||||
return LoadAndUntagToWord32ArrayElement(object, FixedArray::kHeaderSize,
|
||||
index_node, additional_offset,
|
||||
parameter_mode);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::LoadFixedDoubleArrayElement(
|
||||
Node* object, Node* index_node, MachineType machine_type,
|
||||
int additional_offset, ParameterMode parameter_mode, Label* if_hole) {
|
||||
@ -4676,6 +4711,14 @@ Node* CodeStubAssembler::IsFixedArraySubclass(Node* object) {
|
||||
Int32Constant(LAST_FIXED_ARRAY_TYPE)));
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsNotWeakFixedArraySubclass(Node* object) {
|
||||
Node* instance_type = LoadInstanceType(object);
|
||||
return Word32Or(
|
||||
Int32LessThan(instance_type, Int32Constant(FIRST_WEAK_FIXED_ARRAY_TYPE)),
|
||||
Int32GreaterThan(instance_type,
|
||||
Int32Constant(LAST_WEAK_FIXED_ARRAY_TYPE)));
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsPromiseCapability(Node* object) {
|
||||
return HasInstanceType(object, PROMISE_CAPABILITY_TYPE);
|
||||
}
|
||||
@ -6849,6 +6892,9 @@ void CodeStubAssembler::LookupLinear(TNode<Name> unique_name,
|
||||
Label* if_found,
|
||||
TVariable<IntPtrT>* var_name_index,
|
||||
Label* if_not_found) {
|
||||
static_assert(std::is_base_of<FixedArray, Array>::value ||
|
||||
std::is_base_of<TransitionArray, Array>::value,
|
||||
"T must be a descendant of FixedArray or a TransitionArray");
|
||||
Comment("LookupLinear");
|
||||
TNode<IntPtrT> first_inclusive = IntPtrConstant(Array::ToKeyIndex(0));
|
||||
TNode<IntPtrT> factor = IntPtrConstant(Array::kEntrySize);
|
||||
@ -6858,8 +6904,9 @@ void CodeStubAssembler::LookupLinear(TNode<Name> unique_name,
|
||||
|
||||
BuildFastLoop(last_exclusive, first_inclusive,
|
||||
[=](SloppyTNode<IntPtrT> name_index) {
|
||||
TNode<Name> candidate_name =
|
||||
CAST(LoadFixedArrayElement(array, name_index));
|
||||
TNode<Name> candidate_name = CAST(
|
||||
LoadArrayElement(array, Array::kHeaderSize, name_index));
|
||||
CSA_ASSERT(this, IsStrongHeapObject(candidate_name));
|
||||
*var_name_index = name_index;
|
||||
GotoIf(WordEqual(candidate_name, unique_name), if_found);
|
||||
},
|
||||
@ -6877,13 +6924,13 @@ TNode<Uint32T> CodeStubAssembler::NumberOfEntries<DescriptorArray>(
|
||||
template <>
|
||||
TNode<Uint32T> CodeStubAssembler::NumberOfEntries<TransitionArray>(
|
||||
TNode<TransitionArray> transitions) {
|
||||
TNode<IntPtrT> length = LoadAndUntagFixedArrayBaseLength(transitions);
|
||||
TNode<IntPtrT> length = LoadAndUntagWeakFixedArrayLength(transitions);
|
||||
return Select<Uint32T>(
|
||||
UintPtrLessThan(length, IntPtrConstant(TransitionArray::kFirstIndex)),
|
||||
[=] { return Unsigned(Int32Constant(0)); },
|
||||
[=] {
|
||||
return Unsigned(LoadAndUntagToWord32FixedArrayElement(
|
||||
transitions,
|
||||
return Unsigned(LoadAndUntagToWord32ArrayElement(
|
||||
transitions, WeakFixedArray::kHeaderSize,
|
||||
IntPtrConstant(TransitionArray::kTransitionLengthIndex)));
|
||||
});
|
||||
}
|
||||
@ -6924,9 +6971,15 @@ TNode<Uint32T> CodeStubAssembler::GetSortedKeyIndex<TransitionArray>(
|
||||
template <typename Array>
|
||||
TNode<Name> CodeStubAssembler::GetKey(TNode<Array> array,
|
||||
TNode<Uint32T> entry_index) {
|
||||
const int key_offset = DescriptorArray::ToKeyIndex(0) * kPointerSize;
|
||||
return CAST(LoadFixedArrayElement(
|
||||
array, EntryIndexToIndex<Array>(entry_index), key_offset));
|
||||
static_assert(std::is_base_of<FixedArray, Array>::value ||
|
||||
std::is_base_of<TransitionArray, Array>::value,
|
||||
"T must be a descendant of FixedArray or a TransitionArray");
|
||||
const int key_offset = Array::ToKeyIndex(0) * kPointerSize;
|
||||
TNode<Name> key =
|
||||
CAST(LoadArrayElement(array, Array::kHeaderSize,
|
||||
EntryIndexToIndex<Array>(entry_index), key_offset));
|
||||
CSA_ASSERT(this, IsStrongHeapObject(key));
|
||||
return key;
|
||||
}
|
||||
|
||||
template TNode<Name> CodeStubAssembler::GetKey<DescriptorArray>(
|
||||
|
@ -573,6 +573,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
// Load the length of a fixed array base instance.
|
||||
TNode<IntPtrT> LoadAndUntagFixedArrayBaseLength(
|
||||
SloppyTNode<FixedArrayBase> array);
|
||||
// Load the length of a WeakFixedArray.
|
||||
TNode<IntPtrT> LoadAndUntagWeakFixedArrayLength(
|
||||
SloppyTNode<WeakFixedArray> array);
|
||||
// Load the bit field of a Map.
|
||||
TNode<Int32T> LoadMapBitField(SloppyTNode<Map> map);
|
||||
// Load bit field 2 of a map.
|
||||
@ -647,6 +650,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
void DispatchMaybeObject(Node* maybe_object, Label* if_smi, Label* if_cleared,
|
||||
Label* if_weak, Label* if_strong,
|
||||
Variable* extracted);
|
||||
Node* IsStrongHeapObject(Node* value);
|
||||
Node* ToStrongHeapObject(Node* value);
|
||||
|
||||
// Load an array element from a FixedArray / WeakFixedArray.
|
||||
TNode<Object> LoadArrayElement(
|
||||
SloppyTNode<Object> object, int array_header_size, Node* index,
|
||||
int additional_offset = 0,
|
||||
ParameterMode parameter_mode = INTPTR_PARAMETERS,
|
||||
LoadSensitivity needs_poisoning = LoadSensitivity::kSafe);
|
||||
|
||||
// Load an array element from a FixedArray.
|
||||
TNode<Object> LoadFixedArrayElement(
|
||||
@ -679,6 +691,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
TNode<Object> LoadFixedArrayElement(TNode<Object> object, TNode<Smi> index) {
|
||||
return LoadFixedArrayElement(object, index, 0, SMI_PARAMETERS);
|
||||
}
|
||||
|
||||
// Load an array element from a FixedArray / WeakFixedArray, untag it and
|
||||
// return it as Word32.
|
||||
TNode<Int32T> LoadAndUntagToWord32ArrayElement(
|
||||
SloppyTNode<Object> object, int array_header_size, Node* index,
|
||||
int additional_offset = 0,
|
||||
ParameterMode parameter_mode = INTPTR_PARAMETERS);
|
||||
|
||||
// Load an array element from a FixedArray, untag it and return it as Word32.
|
||||
TNode<Int32T> LoadAndUntagToWord32FixedArrayElement(
|
||||
SloppyTNode<Object> object, Node* index, int additional_offset = 0,
|
||||
@ -1339,6 +1359,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
Node* IsWeakCell(Node* object);
|
||||
Node* IsZeroOrContext(Node* object);
|
||||
|
||||
Node* IsNotWeakFixedArraySubclass(Node* object);
|
||||
|
||||
inline Node* IsSharedFunctionInfo(Node* object) {
|
||||
return IsSharedFunctionInfoMap(LoadMap(object));
|
||||
}
|
||||
|
@ -227,6 +227,29 @@ Handle<T> Factory::NewFixedArrayWithMap(Heap::RootListIndex map_root_index,
|
||||
map_root_index, length, *undefined_value(), pretenure));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Handle<T> Factory::NewWeakFixedArrayWithMap(Heap::RootListIndex map_root_index,
|
||||
int length,
|
||||
PretenureFlag pretenure) {
|
||||
static_assert(std::is_base_of<WeakFixedArray, T>::value,
|
||||
"T must be a descendant of WeakFixedArray");
|
||||
|
||||
// Zero-length case must be handled outside.
|
||||
DCHECK_LT(0, length);
|
||||
|
||||
HeapObject* result =
|
||||
AllocateRawArray(WeakFixedArray::SizeFor(length), pretenure);
|
||||
Map* map = Map::cast(isolate()->heap()->root(map_root_index));
|
||||
result->set_map_after_allocation(map, SKIP_WRITE_BARRIER);
|
||||
|
||||
Handle<WeakFixedArray> array(WeakFixedArray::cast(result), isolate());
|
||||
array->set_length(length);
|
||||
MemsetPointer(array->data_start(),
|
||||
HeapObjectReference::Strong(*undefined_value()), length);
|
||||
|
||||
return Handle<T>::cast(array);
|
||||
}
|
||||
|
||||
template Handle<FixedArray> Factory::NewFixedArrayWithMap<FixedArray>(
|
||||
Heap::RootListIndex, int, PretenureFlag);
|
||||
|
||||
@ -1619,8 +1642,10 @@ Handle<WeakCell> Factory::NewWeakCell(Handle<HeapObject> value) {
|
||||
return cell;
|
||||
}
|
||||
|
||||
Handle<TransitionArray> Factory::NewTransitionArray(int capacity) {
|
||||
Handle<TransitionArray> array = NewFixedArrayWithMap<TransitionArray>(
|
||||
Handle<TransitionArray> Factory::NewTransitionArray(int number_of_transitions,
|
||||
int slack) {
|
||||
int capacity = TransitionArray::LengthFor(number_of_transitions + slack);
|
||||
Handle<TransitionArray> array = NewWeakFixedArrayWithMap<TransitionArray>(
|
||||
Heap::kTransitionArrayMapRootIndex, capacity, TENURED);
|
||||
// Transition arrays are tenured. When black allocation is on we have to
|
||||
// add the transition array to the list of encountered_transition_arrays.
|
||||
@ -1628,6 +1653,11 @@ Handle<TransitionArray> Factory::NewTransitionArray(int capacity) {
|
||||
if (heap->incremental_marking()->black_allocation()) {
|
||||
heap->mark_compact_collector()->AddTransitionArray(*array);
|
||||
}
|
||||
array->WeakFixedArray::Set(TransitionArray::kPrototypeTransitionsIndex,
|
||||
MaybeObject::FromObject(Smi::kZero));
|
||||
array->WeakFixedArray::Set(
|
||||
TransitionArray::kTransitionLengthIndex,
|
||||
MaybeObject::FromObject(Smi::FromInt(number_of_transitions)));
|
||||
return array;
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,13 @@ class V8_EXPORT_PRIVATE Factory {
|
||||
Handle<T> NewFixedArrayWithMap(Heap::RootListIndex map_root_index, int length,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
||||
// Allocates a weak fixed array-like object with given map and initialized
|
||||
// with undefined values.
|
||||
template <typename T = WeakFixedArray>
|
||||
Handle<T> NewWeakFixedArrayWithMap(Heap::RootListIndex map_root_index,
|
||||
int length,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
||||
// Allocates a fixed array initialized with undefined values.
|
||||
Handle<FixedArray> NewFixedArray(int length,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
@ -441,7 +448,8 @@ class V8_EXPORT_PRIVATE Factory {
|
||||
Handle<FeedbackCell> NewOneClosureCell(Handle<HeapObject> value);
|
||||
Handle<FeedbackCell> NewManyClosuresCell(Handle<HeapObject> value);
|
||||
|
||||
Handle<TransitionArray> NewTransitionArray(int capacity);
|
||||
Handle<TransitionArray> NewTransitionArray(int number_of_transitions,
|
||||
int slack = 0);
|
||||
|
||||
// Allocate a tenured AllocationSite. Its payload is null.
|
||||
Handle<AllocationSite> NewAllocationSite();
|
||||
|
@ -2853,14 +2853,27 @@ void Heap::RightTrimFixedArray(FixedArrayBase* object, int elements_to_trim) {
|
||||
bytes_to_trim = elements_to_trim * kDoubleSize;
|
||||
}
|
||||
|
||||
CreateFillerForArray<FixedArrayBase>(object, elements_to_trim, bytes_to_trim);
|
||||
}
|
||||
|
||||
void Heap::RightTrimWeakFixedArray(WeakFixedArray* object,
|
||||
int elements_to_trim) {
|
||||
CreateFillerForArray<WeakFixedArray>(object, elements_to_trim,
|
||||
elements_to_trim * kPointerSize);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Heap::CreateFillerForArray(T* object, int elements_to_trim,
|
||||
int bytes_to_trim) {
|
||||
DCHECK(object->IsFixedArrayBase() || object->IsByteArray() ||
|
||||
object->IsWeakFixedArray());
|
||||
|
||||
// For now this trick is only applied to objects in new and paged space.
|
||||
DCHECK(object->map() != fixed_cow_array_map());
|
||||
|
||||
if (bytes_to_trim == 0) {
|
||||
// No need to create filler and update live bytes counters, just initialize
|
||||
// header of the trimmed array.
|
||||
object->synchronized_set_length(len - elements_to_trim);
|
||||
DCHECK_EQ(elements_to_trim, 0);
|
||||
// No need to create filler and update live bytes counters.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2892,7 +2905,7 @@ void Heap::RightTrimFixedArray(FixedArrayBase* object, int elements_to_trim) {
|
||||
// Initialize header of the trimmed array. We are storing the new length
|
||||
// using release store after creating a filler for the left-over space to
|
||||
// avoid races with the sweeper thread.
|
||||
object->synchronized_set_length(len - elements_to_trim);
|
||||
object->synchronized_set_length(object->length() - elements_to_trim);
|
||||
|
||||
// Notify the heap object allocation tracker of change in object layout. The
|
||||
// array may not be moved during GC, and size has to be adjusted nevertheless.
|
||||
|
@ -772,6 +772,9 @@ class Heap {
|
||||
ClearFreedMemoryMode clear_memory_mode =
|
||||
ClearFreedMemoryMode::kDontClearFreedMemory);
|
||||
|
||||
template <typename T>
|
||||
void CreateFillerForArray(T* object, int elements_to_trim, int bytes_to_trim);
|
||||
|
||||
bool CanMoveObjectStart(HeapObject* object);
|
||||
|
||||
static bool IsImmovable(HeapObject* object);
|
||||
@ -782,6 +785,7 @@ class Heap {
|
||||
|
||||
// Trim the given array from the right.
|
||||
void RightTrimFixedArray(FixedArrayBase* obj, int elements_to_trim);
|
||||
void RightTrimWeakFixedArray(WeakFixedArray* obj, int elements_to_trim);
|
||||
|
||||
// Converts the given boolean condition to JavaScript boolean value.
|
||||
inline Oddball* ToBoolean(bool condition);
|
||||
|
@ -1716,7 +1716,8 @@ void MarkCompactCollector::ClearNonLiveReferences() {
|
||||
|
||||
{
|
||||
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_MAPS);
|
||||
// ClearFullMapTransitions must be called before WeakCells are cleared.
|
||||
// ClearFullMapTransitions must be called before weak references are
|
||||
// cleared.
|
||||
ClearFullMapTransitions();
|
||||
}
|
||||
ClearWeakCells();
|
||||
@ -1820,12 +1821,14 @@ bool MarkCompactCollector::CompactTransitionArray(
|
||||
if (i != transition_index) {
|
||||
Name* key = transitions->GetKey(i);
|
||||
transitions->SetKey(transition_index, key);
|
||||
Object** key_slot = transitions->GetKeySlot(transition_index);
|
||||
HeapObjectReference** key_slot =
|
||||
transitions->GetKeySlot(transition_index);
|
||||
RecordSlot(transitions, key_slot, key);
|
||||
Object* raw_target = transitions->GetRawTarget(i);
|
||||
transitions->SetTarget(transition_index, raw_target);
|
||||
Object** target_slot = transitions->GetTargetSlot(transition_index);
|
||||
RecordSlot(transitions, target_slot, raw_target);
|
||||
MaybeObject* raw_target = transitions->GetRawTarget(i);
|
||||
transitions->SetRawTarget(transition_index, raw_target);
|
||||
HeapObjectReference** target_slot =
|
||||
transitions->GetTargetSlot(transition_index);
|
||||
RecordSlot(transitions, target_slot, raw_target->GetHeapObject());
|
||||
}
|
||||
transition_index++;
|
||||
}
|
||||
@ -1841,7 +1844,8 @@ bool MarkCompactCollector::CompactTransitionArray(
|
||||
// array disappeared during GC.
|
||||
int trim = transitions->Capacity() - transition_index;
|
||||
if (trim > 0) {
|
||||
heap_->RightTrimFixedArray(transitions, trim * TransitionArray::kEntrySize);
|
||||
heap_->RightTrimWeakFixedArray(transitions,
|
||||
trim * TransitionArray::kEntrySize);
|
||||
transitions->SetNumberOfTransitions(transition_index);
|
||||
}
|
||||
return descriptors_owner_died;
|
||||
|
@ -732,10 +732,9 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
|
||||
const int kKeyToTargetOffset = (TransitionArray::kEntryTargetIndex -
|
||||
TransitionArray::kEntryKeyIndex) *
|
||||
kPointerSize;
|
||||
TNode<WeakCell> transition_map_weak_cell = CAST(LoadFixedArrayElement(
|
||||
transitions, var_name_index.value(), kKeyToTargetOffset));
|
||||
var_transition_map =
|
||||
CAST(LoadWeakCellValue(transition_map_weak_cell, slow));
|
||||
var_transition_map = CAST(ToStrongHeapObject(
|
||||
LoadArrayElement(transitions, WeakFixedArray::kHeaderSize,
|
||||
var_name_index.value(), kKeyToTargetOffset)));
|
||||
Goto(&found_handler_candidate);
|
||||
}
|
||||
}
|
||||
|
@ -634,7 +634,7 @@ void DescriptorArray::DescriptorArrayVerify() {
|
||||
}
|
||||
|
||||
void TransitionArray::TransitionArrayVerify() {
|
||||
FixedArrayVerify();
|
||||
WeakFixedArrayVerify();
|
||||
CHECK_LE(LengthFor(number_of_transitions()), length());
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,12 @@ bool HeapObject::IsFixedArray() const {
|
||||
instance_type <= LAST_FIXED_ARRAY_TYPE;
|
||||
}
|
||||
|
||||
bool HeapObject::IsWeakFixedArray() const {
|
||||
InstanceType instance_type = map()->instance_type();
|
||||
return instance_type >= FIRST_WEAK_FIXED_ARRAY_TYPE &&
|
||||
instance_type <= LAST_WEAK_FIXED_ARRAY_TYPE;
|
||||
}
|
||||
|
||||
bool HeapObject::IsSloppyArgumentsElements() const {
|
||||
return IsFixedArrayExact();
|
||||
}
|
||||
@ -2238,7 +2244,8 @@ int HeapObject::SizeFromMap(Map* map) const {
|
||||
reinterpret_cast<const FeedbackMetadata*>(this)
|
||||
->synchronized_slot_count());
|
||||
}
|
||||
if (instance_type == WEAK_FIXED_ARRAY_TYPE) {
|
||||
if (instance_type >= FIRST_WEAK_FIXED_ARRAY_TYPE &&
|
||||
instance_type <= LAST_WEAK_FIXED_ARRAY_TYPE) {
|
||||
return WeakFixedArray::SizeFor(
|
||||
reinterpret_cast<const WeakFixedArray*>(this)->synchronized_length());
|
||||
}
|
||||
|
@ -815,7 +815,7 @@ void TransitionArray::TransitionArrayPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "TransitionArray");
|
||||
os << "\n - capacity: " << length();
|
||||
for (int i = 0; i < length(); i++) {
|
||||
os << "\n [" << i << "]: " << Brief(get(i));
|
||||
os << "\n [" << i << "]: " << MaybeObjectBrief(Get(i));
|
||||
if (i == kPrototypeTransitionsIndex) os << " (prototype transitions)";
|
||||
if (i == kTransitionLengthIndex) os << " (number of transitions)";
|
||||
}
|
||||
|
@ -10158,6 +10158,12 @@ bool FixedArray::IsEqualTo(FixedArray* other) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void WeakFixedArray::Shrink(int new_length) {
|
||||
DCHECK(0 <= new_length && new_length <= length());
|
||||
if (new_length < length()) {
|
||||
GetHeap()->RightTrimWeakFixedArray(this, length() - new_length);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void FixedArrayOfWeakCells::Set(Handle<FixedArrayOfWeakCells> array, int index,
|
||||
|
@ -412,7 +412,6 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(DESCRIPTOR_ARRAY_TYPE) \
|
||||
V(HASH_TABLE_TYPE) \
|
||||
V(SCOPE_INFO_TYPE) \
|
||||
V(TRANSITION_ARRAY_TYPE) \
|
||||
\
|
||||
V(BLOCK_CONTEXT_TYPE) \
|
||||
V(CATCH_CONTEXT_TYPE) \
|
||||
@ -424,6 +423,9 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(SCRIPT_CONTEXT_TYPE) \
|
||||
V(WITH_CONTEXT_TYPE) \
|
||||
\
|
||||
V(WEAK_FIXED_ARRAY_TYPE) \
|
||||
V(TRANSITION_ARRAY_TYPE) \
|
||||
\
|
||||
V(CALL_HANDLER_INFO_TYPE) \
|
||||
V(CELL_TYPE) \
|
||||
V(CODE_DATA_CONTAINER_TYPE) \
|
||||
@ -437,7 +439,6 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(SMALL_ORDERED_HASH_SET_TYPE) \
|
||||
V(STORE_HANDLER_TYPE) \
|
||||
V(WEAK_CELL_TYPE) \
|
||||
V(WEAK_FIXED_ARRAY_TYPE) \
|
||||
V(WEAK_ARRAY_LIST_TYPE) \
|
||||
\
|
||||
V(JS_PROXY_TYPE) \
|
||||
@ -782,7 +783,6 @@ enum InstanceType : uint16_t {
|
||||
DESCRIPTOR_ARRAY_TYPE,
|
||||
HASH_TABLE_TYPE,
|
||||
SCOPE_INFO_TYPE,
|
||||
TRANSITION_ARRAY_TYPE,
|
||||
BLOCK_CONTEXT_TYPE, // FIRST_CONTEXT_TYPE
|
||||
CATCH_CONTEXT_TYPE,
|
||||
DEBUG_EVALUATE_CONTEXT_TYPE,
|
||||
@ -793,6 +793,9 @@ enum InstanceType : uint16_t {
|
||||
SCRIPT_CONTEXT_TYPE,
|
||||
WITH_CONTEXT_TYPE, // LAST_FIXED_ARRAY_TYPE, LAST_CONTEXT_TYPE
|
||||
|
||||
WEAK_FIXED_ARRAY_TYPE, // FIRST_WEAK_FIXED_ARRAY_TYPE
|
||||
TRANSITION_ARRAY_TYPE, // LAST_WEAK_FIXED_ARRAY_TYPE
|
||||
|
||||
// Misc.
|
||||
CALL_HANDLER_INFO_TYPE,
|
||||
CELL_TYPE,
|
||||
@ -807,7 +810,6 @@ enum InstanceType : uint16_t {
|
||||
SMALL_ORDERED_HASH_SET_TYPE,
|
||||
STORE_HANDLER_TYPE,
|
||||
WEAK_CELL_TYPE,
|
||||
WEAK_FIXED_ARRAY_TYPE,
|
||||
WEAK_ARRAY_LIST_TYPE,
|
||||
|
||||
// All the following types are subtypes of JSReceiver, which corresponds to
|
||||
@ -879,6 +881,9 @@ enum InstanceType : uint16_t {
|
||||
// Boundaries for testing if given HeapObject is a subclass of FixedArray.
|
||||
FIRST_FIXED_ARRAY_TYPE = FIXED_ARRAY_TYPE,
|
||||
LAST_FIXED_ARRAY_TYPE = WITH_CONTEXT_TYPE,
|
||||
// Boundaries for testing if given HeapObject is a subclass of WeakFixedArray.
|
||||
FIRST_WEAK_FIXED_ARRAY_TYPE = WEAK_FIXED_ARRAY_TYPE,
|
||||
LAST_WEAK_FIXED_ARRAY_TYPE = TRANSITION_ARRAY_TYPE,
|
||||
// Boundaries for testing if given HeapObject is a Context
|
||||
FIRST_CONTEXT_TYPE = BLOCK_CONTEXT_TYPE,
|
||||
LAST_CONTEXT_TYPE = WITH_CONTEXT_TYPE,
|
||||
|
@ -17,7 +17,6 @@ TYPE_CHECKER(ByteArray, BYTE_ARRAY_TYPE)
|
||||
TYPE_CHECKER(FixedArrayExact, FIXED_ARRAY_TYPE)
|
||||
TYPE_CHECKER(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE)
|
||||
TYPE_CHECKER(FixedArrayOfWeakCells, FIXED_ARRAY_TYPE)
|
||||
TYPE_CHECKER(WeakFixedArray, WEAK_FIXED_ARRAY_TYPE)
|
||||
TYPE_CHECKER(WeakArrayList, WEAK_ARRAY_LIST_TYPE)
|
||||
|
||||
CAST_ACCESSOR(ArrayList)
|
||||
@ -242,6 +241,10 @@ MaybeObject** WeakFixedArray::data_start() {
|
||||
return HeapObject::RawMaybeWeakField(this, kHeaderSize);
|
||||
}
|
||||
|
||||
MaybeObject** WeakFixedArray::RawFieldOfElementAt(int index) {
|
||||
return HeapObject::RawMaybeWeakField(this, OffsetOfElementAt(index));
|
||||
}
|
||||
|
||||
MaybeObject* WeakArrayList::Get(int index) const {
|
||||
SLOW_DCHECK(index >= 0 && index < this->capacity());
|
||||
return RELAXED_READ_WEAK_FIELD(this, OffsetOfElementAt(index));
|
||||
|
@ -269,6 +269,11 @@ class WeakFixedArray : public HeapObject {
|
||||
// Gives access to raw memory which stores the array's data.
|
||||
inline MaybeObject** data_start();
|
||||
|
||||
inline MaybeObject** RawFieldOfElementAt(int index);
|
||||
|
||||
// Shrink length and insert filler objects.
|
||||
void Shrink(int new_length);
|
||||
|
||||
DECL_PRINTER(WeakFixedArray)
|
||||
DECL_VERIFIER(WeakFixedArray)
|
||||
|
||||
|
@ -1349,6 +1349,7 @@ void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
|
||||
auto it = array_types_.find(array);
|
||||
if (it == array_types_.end()) {
|
||||
for (int i = 0, l = array->length(); i < l; ++i) {
|
||||
DCHECK(!HasWeakHeapObjectTag(array->get(i)));
|
||||
SetInternalReference(array, entry, i, array->get(i),
|
||||
array->OffsetOfElementAt(i));
|
||||
}
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "src/transitions.h"
|
||||
|
||||
#include "src/ic/handler-configuration-inl.h"
|
||||
#include "src/objects/fixed-array-inl.h"
|
||||
#include "src/objects/maybe-object-inl.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
@ -23,37 +25,33 @@ TransitionArray* TransitionsAccessor::transitions() {
|
||||
CAST_ACCESSOR(TransitionArray)
|
||||
|
||||
bool TransitionArray::HasPrototypeTransitions() {
|
||||
return get(kPrototypeTransitionsIndex) != Smi::kZero;
|
||||
return Get(kPrototypeTransitionsIndex) != MaybeObject::FromSmi(Smi::kZero);
|
||||
}
|
||||
|
||||
|
||||
FixedArray* TransitionArray::GetPrototypeTransitions() {
|
||||
DCHECK(HasPrototypeTransitions()); // Callers must check first.
|
||||
Object* prototype_transitions = get(kPrototypeTransitionsIndex);
|
||||
Object* prototype_transitions =
|
||||
Get(kPrototypeTransitionsIndex)->ToStrongHeapObject();
|
||||
return FixedArray::cast(prototype_transitions);
|
||||
}
|
||||
|
||||
HeapObjectReference** TransitionArray::GetKeySlot(int transition_number) {
|
||||
DCHECK(transition_number < number_of_transitions());
|
||||
return reinterpret_cast<HeapObjectReference**>(
|
||||
RawFieldOfElementAt(ToKeyIndex(transition_number)));
|
||||
}
|
||||
|
||||
void TransitionArray::SetPrototypeTransitions(FixedArray* transitions) {
|
||||
DCHECK(transitions->IsFixedArray());
|
||||
set(kPrototypeTransitionsIndex, transitions);
|
||||
}
|
||||
|
||||
|
||||
Object** TransitionArray::GetPrototypeTransitionsSlot() {
|
||||
return RawFieldOfElementAt(kPrototypeTransitionsIndex);
|
||||
}
|
||||
|
||||
|
||||
Object** TransitionArray::GetKeySlot(int transition_number) {
|
||||
DCHECK(transition_number < number_of_transitions());
|
||||
return RawFieldOfElementAt(ToKeyIndex(transition_number));
|
||||
WeakFixedArray::Set(kPrototypeTransitionsIndex,
|
||||
HeapObjectReference::Strong(transitions));
|
||||
}
|
||||
|
||||
|
||||
Name* TransitionArray::GetKey(int transition_number) {
|
||||
DCHECK(transition_number < number_of_transitions());
|
||||
return Name::cast(get(ToKeyIndex(transition_number)));
|
||||
return Name::cast(Get(ToKeyIndex(transition_number))->ToStrongHeapObject());
|
||||
}
|
||||
|
||||
Name* TransitionsAccessor::GetKey(int transition_number) {
|
||||
@ -74,12 +72,14 @@ Name* TransitionsAccessor::GetKey(int transition_number) {
|
||||
|
||||
void TransitionArray::SetKey(int transition_number, Name* key) {
|
||||
DCHECK(transition_number < number_of_transitions());
|
||||
set(ToKeyIndex(transition_number), key);
|
||||
WeakFixedArray::Set(ToKeyIndex(transition_number),
|
||||
HeapObjectReference::Strong(key));
|
||||
}
|
||||
|
||||
Object** TransitionArray::GetTargetSlot(int transition_number) {
|
||||
HeapObjectReference** TransitionArray::GetTargetSlot(int transition_number) {
|
||||
DCHECK(transition_number < number_of_transitions());
|
||||
return RawFieldOfElementAt(ToTargetIndex(transition_number));
|
||||
return reinterpret_cast<HeapObjectReference**>(
|
||||
RawFieldOfElementAt(ToTargetIndex(transition_number)));
|
||||
}
|
||||
|
||||
// static
|
||||
@ -93,17 +93,17 @@ PropertyDetails TransitionsAccessor::GetTargetDetails(Name* name, Map* target) {
|
||||
}
|
||||
|
||||
// static
|
||||
Map* TransitionsAccessor::GetTargetFromRaw(Object* raw) {
|
||||
return Map::cast(WeakCell::cast(raw)->value());
|
||||
Map* TransitionsAccessor::GetTargetFromRaw(MaybeObject* raw) {
|
||||
return Map::cast(raw->ToWeakHeapObject());
|
||||
}
|
||||
|
||||
Object* TransitionArray::GetRawTarget(int transition_number) {
|
||||
MaybeObject* TransitionArray::GetRawTarget(int transition_number) {
|
||||
DCHECK(transition_number < number_of_transitions());
|
||||
return get(ToTargetIndex(transition_number));
|
||||
return Get(ToTargetIndex(transition_number));
|
||||
}
|
||||
|
||||
Map* TransitionArray::GetTarget(int transition_number) {
|
||||
Object* raw = GetRawTarget(transition_number);
|
||||
MaybeObject* raw = GetRawTarget(transition_number);
|
||||
return TransitionsAccessor::GetTargetFromRaw(raw);
|
||||
}
|
||||
|
||||
@ -121,16 +121,18 @@ Map* TransitionsAccessor::GetTarget(int transition_number) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void TransitionArray::SetTarget(int transition_number, Object* value) {
|
||||
DCHECK(!value->IsMap());
|
||||
void TransitionArray::SetRawTarget(int transition_number, MaybeObject* value) {
|
||||
DCHECK(transition_number < number_of_transitions());
|
||||
set(ToTargetIndex(transition_number), value);
|
||||
DCHECK(value->IsWeakHeapObject() && value->ToWeakHeapObject()->IsMap());
|
||||
WeakFixedArray::Set(ToTargetIndex(transition_number), value);
|
||||
}
|
||||
|
||||
bool TransitionArray::GetTargetIfExists(int transition_number, Isolate* isolate,
|
||||
Map** target) {
|
||||
Object* raw = GetRawTarget(transition_number);
|
||||
if (raw->IsUndefined(isolate)) {
|
||||
MaybeObject* raw = GetRawTarget(transition_number);
|
||||
HeapObject* heap_object;
|
||||
if (raw->ToStrongHeapObject(&heap_object) &&
|
||||
heap_object->IsUndefined(isolate)) {
|
||||
return false;
|
||||
}
|
||||
*target = TransitionsAccessor::GetTargetFromRaw(raw);
|
||||
@ -143,6 +145,11 @@ int TransitionArray::SearchName(Name* name, int* out_insertion_index) {
|
||||
out_insertion_index);
|
||||
}
|
||||
|
||||
int TransitionArray::number_of_transitions() const {
|
||||
if (length() < kFirstIndex) return 0;
|
||||
return Smi::ToInt(Get(kTransitionLengthIndex)->ToSmi());
|
||||
}
|
||||
|
||||
int TransitionArray::CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1,
|
||||
PropertyAttributes attributes1, Name* key2,
|
||||
uint32_t hash2, PropertyKind kind2,
|
||||
@ -179,9 +186,11 @@ int TransitionArray::CompareDetails(PropertyKind kind1,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TransitionArray::Set(int transition_number, Name* key, Object* target) {
|
||||
set(ToKeyIndex(transition_number), key);
|
||||
set(ToTargetIndex(transition_number), target);
|
||||
void TransitionArray::Set(int transition_number, Name* key,
|
||||
MaybeObject* target) {
|
||||
WeakFixedArray::Set(ToKeyIndex(transition_number),
|
||||
MaybeObject::FromObject(key));
|
||||
WeakFixedArray::Set(ToTargetIndex(transition_number), target);
|
||||
}
|
||||
|
||||
int TransitionArray::Capacity() {
|
||||
@ -191,7 +200,9 @@ int TransitionArray::Capacity() {
|
||||
|
||||
void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
|
||||
DCHECK(number_of_transitions <= Capacity());
|
||||
set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
|
||||
WeakFixedArray::Set(
|
||||
kTransitionLengthIndex,
|
||||
MaybeObject::FromSmi(Smi::FromInt(number_of_transitions)));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -68,7 +68,8 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
return;
|
||||
}
|
||||
// If the flag requires a full TransitionArray, allocate one.
|
||||
Handle<TransitionArray> result = TransitionArray::Allocate(isolate, 0, 1);
|
||||
Handle<TransitionArray> result =
|
||||
isolate->factory()->NewTransitionArray(0, 1);
|
||||
ReplaceTransitions(MaybeObject::FromObject(*result));
|
||||
Reload();
|
||||
}
|
||||
@ -90,15 +91,16 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
}
|
||||
// Otherwise allocate a full TransitionArray with slack for a new entry.
|
||||
Handle<Map> map(simple_transition);
|
||||
Handle<WeakCell> weak_cell = Map::WeakCellForMap(map);
|
||||
Handle<TransitionArray> result = TransitionArray::Allocate(isolate, 1, 1);
|
||||
Handle<TransitionArray> result =
|
||||
isolate->factory()->NewTransitionArray(1, 1);
|
||||
// Reload state; allocations might have caused it to be cleared.
|
||||
Reload();
|
||||
simple_transition = GetSimpleTransition();
|
||||
if (simple_transition != nullptr) {
|
||||
DCHECK_EQ(*map, simple_transition);
|
||||
if (encoding_ == kWeakRef) {
|
||||
result->Set(0, GetSimpleTransitionKey(simple_transition), *weak_cell);
|
||||
result->Set(0, GetSimpleTransitionKey(simple_transition),
|
||||
HeapObjectReference::Weak(simple_transition));
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -112,9 +114,6 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
// At this point, we know that the map has a full TransitionArray.
|
||||
DCHECK_EQ(kFullTransitionArray, encoding());
|
||||
|
||||
Handle<WeakCell> weak_cell_with_target = Map::WeakCellForMap(target);
|
||||
Reload();
|
||||
|
||||
int number_of_transitions = 0;
|
||||
int new_nof = 0;
|
||||
int insertion_index = kNotFound;
|
||||
@ -136,7 +135,7 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
&insertion_index);
|
||||
// If an existing entry was found, overwrite it and return.
|
||||
if (index != kNotFound) {
|
||||
array->SetTarget(index, *weak_cell_with_target);
|
||||
array->SetRawTarget(index, HeapObjectReference::Weak(*target));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -149,18 +148,18 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
array->SetNumberOfTransitions(new_nof);
|
||||
for (index = number_of_transitions; index > insertion_index; --index) {
|
||||
array->SetKey(index, array->GetKey(index - 1));
|
||||
array->SetTarget(index, array->GetRawTarget(index - 1));
|
||||
array->SetRawTarget(index, array->GetRawTarget(index - 1));
|
||||
}
|
||||
array->SetKey(index, *name);
|
||||
array->SetTarget(index, *weak_cell_with_target);
|
||||
array->SetRawTarget(index, HeapObjectReference::Weak(*target));
|
||||
SLOW_DCHECK(array->IsSortedNoDuplicates());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We're gonna need a bigger TransitionArray.
|
||||
Handle<TransitionArray> result = TransitionArray::Allocate(
|
||||
isolate, new_nof,
|
||||
Handle<TransitionArray> result = isolate->factory()->NewTransitionArray(
|
||||
new_nof,
|
||||
Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
|
||||
|
||||
// The map's transition array may have shrunk during the allocation above as
|
||||
@ -200,7 +199,7 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
for (int i = 0; i < insertion_index; ++i) {
|
||||
result->Set(i, array->GetKey(i), array->GetRawTarget(i));
|
||||
}
|
||||
result->Set(insertion_index, *name, *weak_cell_with_target);
|
||||
result->Set(insertion_index, *name, HeapObjectReference::Weak(*target));
|
||||
for (int i = insertion_index; i < number_of_transitions; ++i) {
|
||||
result->Set(i + 1, array->GetKey(i), array->GetRawTarget(i));
|
||||
}
|
||||
@ -436,19 +435,9 @@ int TransitionsAccessor::NumberOfTransitions() {
|
||||
return 0; // Make GCC happy.
|
||||
}
|
||||
|
||||
Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
|
||||
int number_of_transitions,
|
||||
int slack) {
|
||||
Handle<FixedArray> array = isolate->factory()->NewTransitionArray(
|
||||
LengthFor(number_of_transitions + slack));
|
||||
array->set(kPrototypeTransitionsIndex, Smi::kZero);
|
||||
array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
|
||||
return Handle<TransitionArray>::cast(array);
|
||||
}
|
||||
|
||||
void TransitionArray::Zap() {
|
||||
MemsetPointer(data_start() + kPrototypeTransitionsIndex,
|
||||
GetHeap()->the_hole_value(),
|
||||
MaybeObject::FromObject(GetHeap()->the_hole_value()),
|
||||
length() - kPrototypeTransitionsIndex);
|
||||
SetNumberOfTransitions(0);
|
||||
}
|
||||
@ -481,7 +470,7 @@ void TransitionsAccessor::EnsureHasFullTransitionArray() {
|
||||
if (encoding() == kFullTransitionArray) return;
|
||||
int nof = encoding() == kUninitialized ? 0 : 1;
|
||||
Handle<TransitionArray> result =
|
||||
TransitionArray::Allocate(map_->GetIsolate(), nof);
|
||||
map_->GetIsolate()->factory()->NewTransitionArray(nof);
|
||||
Reload(); // Reload after possible GC.
|
||||
if (nof == 1) {
|
||||
if (encoding() == kUninitialized) {
|
||||
@ -491,10 +480,8 @@ void TransitionsAccessor::EnsureHasFullTransitionArray() {
|
||||
} else {
|
||||
// Otherwise populate the new array.
|
||||
Handle<Map> target(GetSimpleTransition());
|
||||
Handle<WeakCell> weak_cell_with_target = Map::WeakCellForMap(target);
|
||||
Reload(); // Reload after possible GC.
|
||||
Name* key = GetSimpleTransitionKey(*target);
|
||||
result->Set(0, key, *weak_cell_with_target);
|
||||
result->Set(0, key, HeapObjectReference::Weak(*target));
|
||||
}
|
||||
}
|
||||
ReplaceTransitions(MaybeObject::FromObject(*result));
|
||||
@ -601,7 +588,7 @@ void TransitionArray::Sort() {
|
||||
int length = number_of_transitions();
|
||||
for (int i = 1; i < length; i++) {
|
||||
Name* key = GetKey(i);
|
||||
Object* target = GetRawTarget(i);
|
||||
MaybeObject* target = GetRawTarget(i);
|
||||
PropertyKind kind = kData;
|
||||
PropertyAttributes attributes = NONE;
|
||||
if (!TransitionsAccessor::IsSpecialTransition(key)) {
|
||||
@ -614,7 +601,7 @@ void TransitionArray::Sort() {
|
||||
int j;
|
||||
for (j = i - 1; j >= 0; j--) {
|
||||
Name* temp_key = GetKey(j);
|
||||
Object* temp_target = GetRawTarget(j);
|
||||
MaybeObject* temp_target = GetRawTarget(j);
|
||||
PropertyKind temp_kind = kData;
|
||||
PropertyAttributes temp_attributes = NONE;
|
||||
if (!TransitionsAccessor::IsSpecialTransition(temp_key)) {
|
||||
@ -630,13 +617,13 @@ void TransitionArray::Sort() {
|
||||
key, key->Hash(), kind, attributes);
|
||||
if (cmp > 0) {
|
||||
SetKey(j + 1, temp_key);
|
||||
SetTarget(j + 1, temp_target);
|
||||
SetRawTarget(j + 1, temp_target);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetKey(j + 1, key);
|
||||
SetTarget(j + 1, target);
|
||||
SetRawTarget(j + 1, target);
|
||||
}
|
||||
DCHECK(IsSortedNoDuplicates());
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ class TransitionsAccessor {
|
||||
return transition->instance_descriptors()->GetKey(descriptor);
|
||||
}
|
||||
|
||||
static inline Map* GetTargetFromRaw(Object* raw);
|
||||
static inline Map* GetTargetFromRaw(MaybeObject* raw);
|
||||
|
||||
void MarkNeedsReload() {
|
||||
#if DEBUG
|
||||
@ -193,30 +193,29 @@ class TransitionsAccessor {
|
||||
// The TransitionArray class exposes a very low-level interface. Most clients
|
||||
// should use TransitionsAccessors.
|
||||
// TransitionArrays have the following format:
|
||||
// [0] Link to next TransitionArray (for weak handling support)
|
||||
// [1] Smi(0) or fixed array of prototype transitions
|
||||
// [0] Link to next TransitionArray (for weak handling support) (strong ref)
|
||||
// [1] Smi(0) or fixed array of prototype transitions (strong ref)
|
||||
// [2] Number of transitions (can be zero after trimming)
|
||||
// [3] First transition key
|
||||
// [4] First transition target
|
||||
// [3] First transition key (strong ref)
|
||||
// [4] First transition target (weak ref)
|
||||
// ...
|
||||
// [3 + number of transitions * kTransitionSize]: start of slack
|
||||
class TransitionArray : public FixedArray {
|
||||
class TransitionArray : public WeakFixedArray {
|
||||
public:
|
||||
DECL_CAST(TransitionArray)
|
||||
|
||||
inline FixedArray* GetPrototypeTransitions();
|
||||
inline Object** GetPrototypeTransitionsSlot();
|
||||
inline bool HasPrototypeTransitions();
|
||||
|
||||
// Accessors for fetching instance transition at transition number.
|
||||
inline void SetKey(int transition_number, Name* value);
|
||||
inline Name* GetKey(int transition_number);
|
||||
inline Object** GetKeySlot(int transition_number);
|
||||
inline HeapObjectReference** GetKeySlot(int transition_number);
|
||||
|
||||
inline Map* GetTarget(int transition_number);
|
||||
inline void SetTarget(int transition_number, Object* target);
|
||||
inline Object* GetRawTarget(int transition_number);
|
||||
inline Object** GetTargetSlot(int transition_number);
|
||||
inline void SetRawTarget(int transition_number, MaybeObject* target);
|
||||
inline MaybeObject* GetRawTarget(int transition_number);
|
||||
inline HeapObjectReference** GetTargetSlot(int transition_number);
|
||||
inline bool GetTargetIfExists(int transition_number, Isolate* isolate,
|
||||
Map** target);
|
||||
|
||||
@ -267,6 +266,7 @@ class TransitionArray : public FixedArray {
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Factory;
|
||||
friend class MarkCompactCollector;
|
||||
friend class TransitionsAccessor;
|
||||
|
||||
@ -300,11 +300,6 @@ class TransitionArray : public FixedArray {
|
||||
return ToKeyIndex(number_of_transitions);
|
||||
}
|
||||
|
||||
// Allocates a TransitionArray.
|
||||
static Handle<TransitionArray> Allocate(Isolate* isolate,
|
||||
int number_of_transitions,
|
||||
int slack = 0);
|
||||
|
||||
// Search a transition for a given kind, property name and attributes.
|
||||
int Search(PropertyKind kind, Name* name, PropertyAttributes attributes,
|
||||
int* out_insertion_index = nullptr);
|
||||
@ -319,10 +314,7 @@ class TransitionArray : public FixedArray {
|
||||
int SearchDetails(int transition, PropertyKind kind,
|
||||
PropertyAttributes attributes, int* out_insertion_index);
|
||||
|
||||
int number_of_transitions() const {
|
||||
if (length() < kFirstIndex) return 0;
|
||||
return Smi::ToInt(get(kTransitionLengthIndex));
|
||||
}
|
||||
inline int number_of_transitions() const;
|
||||
|
||||
static bool CompactPrototypeTransitionArray(FixedArray* array);
|
||||
|
||||
@ -348,7 +340,7 @@ class TransitionArray : public FixedArray {
|
||||
PropertyKind kind2,
|
||||
PropertyAttributes attributes2);
|
||||
|
||||
inline void Set(int transition_number, Name* key, Object* target);
|
||||
inline void Set(int transition_number, Name* key, MaybeObject* target);
|
||||
|
||||
void Zap();
|
||||
|
||||
|
@ -5497,13 +5497,14 @@ TEST(ContinuousLeftTrimFixedArrayInBlackArea) {
|
||||
heap::GcAndSweep(heap, OLD_SPACE);
|
||||
}
|
||||
|
||||
TEST(ContinuousRightTrimFixedArrayInBlackArea) {
|
||||
template <typename T, typename NewFunction, typename TrimFunction>
|
||||
void ContinuousRightTrimFixedArrayInBlackAreaHelper(NewFunction& new_func,
|
||||
TrimFunction& trim_func) {
|
||||
if (!FLAG_incremental_marking) return;
|
||||
FLAG_black_allocation = true;
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Heap* heap = CcTest::heap();
|
||||
Isolate* isolate = heap->isolate();
|
||||
CcTest::CollectAllGarbage();
|
||||
|
||||
i::MarkCompactCollector* collector = heap->mark_compact_collector();
|
||||
@ -5522,10 +5523,10 @@ TEST(ContinuousRightTrimFixedArrayInBlackArea) {
|
||||
// Ensure that we allocate a new page, set up a bump pointer area, and
|
||||
// perform the allocation in a black area.
|
||||
heap::SimulateFullSpace(heap->old_space());
|
||||
isolate->factory()->NewFixedArray(10, TENURED);
|
||||
new_func(10, TENURED);
|
||||
|
||||
// Allocate the fixed array that will be trimmed later.
|
||||
Handle<FixedArray> array = isolate->factory()->NewFixedArray(100, TENURED);
|
||||
Handle<T> array = new_func(100, TENURED);
|
||||
Address start_address = array->address();
|
||||
Address end_address = start_address + array->Size();
|
||||
Page* page = Page::FromAddress(start_address);
|
||||
@ -5539,7 +5540,7 @@ TEST(ContinuousRightTrimFixedArrayInBlackArea) {
|
||||
|
||||
// Trim it once by one word to make checking for white marking color uniform.
|
||||
Address previous = end_address - kPointerSize;
|
||||
heap->RightTrimFixedArray(*array, 1);
|
||||
trim_func(*array, 1);
|
||||
HeapObject* filler = HeapObject::FromAddress(previous);
|
||||
CHECK(filler->IsFiller());
|
||||
CHECK(marking_state->IsImpossible(filler));
|
||||
@ -5548,7 +5549,7 @@ TEST(ContinuousRightTrimFixedArrayInBlackArea) {
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
previous -= kPointerSize * i;
|
||||
heap->RightTrimFixedArray(*array, i);
|
||||
trim_func(*array, i);
|
||||
HeapObject* filler = HeapObject::FromAddress(previous);
|
||||
CHECK(filler->IsFiller());
|
||||
CHECK(marking_state->IsWhite(filler));
|
||||
@ -5558,6 +5559,29 @@ TEST(ContinuousRightTrimFixedArrayInBlackArea) {
|
||||
heap::GcAndSweep(heap, OLD_SPACE);
|
||||
}
|
||||
|
||||
TEST(ContinuousRightTrimFixedArrayInBlackArea) {
|
||||
auto new_func = [](int size, PretenureFlag tenured) {
|
||||
return CcTest::i_isolate()->factory()->NewFixedArray(size, tenured);
|
||||
};
|
||||
auto trim_func = [](FixedArray* array, int elements_to_trim) {
|
||||
CcTest::i_isolate()->heap()->RightTrimFixedArray(array, elements_to_trim);
|
||||
};
|
||||
ContinuousRightTrimFixedArrayInBlackAreaHelper<FixedArray>(new_func,
|
||||
trim_func);
|
||||
}
|
||||
|
||||
TEST(ContinuousRightTrimWeakFixedArrayInBlackArea) {
|
||||
auto new_func = [](int size, PretenureFlag tenured) {
|
||||
return CcTest::i_isolate()->factory()->NewWeakFixedArray(size, tenured);
|
||||
};
|
||||
auto trim_func = [](WeakFixedArray* array, int elements_to_trim) {
|
||||
CcTest::i_isolate()->heap()->RightTrimWeakFixedArray(array,
|
||||
elements_to_trim);
|
||||
};
|
||||
ContinuousRightTrimFixedArrayInBlackAreaHelper<WeakFixedArray>(new_func,
|
||||
trim_func);
|
||||
}
|
||||
|
||||
TEST(Regress618958) {
|
||||
if (!FLAG_incremental_marking) return;
|
||||
CcTest::InitializeVM();
|
||||
|
@ -89,30 +89,30 @@ INSTANCE_TYPES = {
|
||||
185: "DESCRIPTOR_ARRAY_TYPE",
|
||||
186: "HASH_TABLE_TYPE",
|
||||
187: "SCOPE_INFO_TYPE",
|
||||
188: "TRANSITION_ARRAY_TYPE",
|
||||
189: "BLOCK_CONTEXT_TYPE",
|
||||
190: "CATCH_CONTEXT_TYPE",
|
||||
191: "DEBUG_EVALUATE_CONTEXT_TYPE",
|
||||
192: "EVAL_CONTEXT_TYPE",
|
||||
193: "FUNCTION_CONTEXT_TYPE",
|
||||
194: "MODULE_CONTEXT_TYPE",
|
||||
195: "NATIVE_CONTEXT_TYPE",
|
||||
196: "SCRIPT_CONTEXT_TYPE",
|
||||
197: "WITH_CONTEXT_TYPE",
|
||||
198: "CALL_HANDLER_INFO_TYPE",
|
||||
199: "CELL_TYPE",
|
||||
200: "CODE_DATA_CONTAINER_TYPE",
|
||||
201: "FEEDBACK_CELL_TYPE",
|
||||
202: "FEEDBACK_VECTOR_TYPE",
|
||||
203: "LOAD_HANDLER_TYPE",
|
||||
204: "PROPERTY_ARRAY_TYPE",
|
||||
205: "PROPERTY_CELL_TYPE",
|
||||
206: "SHARED_FUNCTION_INFO_TYPE",
|
||||
207: "SMALL_ORDERED_HASH_MAP_TYPE",
|
||||
208: "SMALL_ORDERED_HASH_SET_TYPE",
|
||||
209: "STORE_HANDLER_TYPE",
|
||||
210: "WEAK_CELL_TYPE",
|
||||
211: "WEAK_FIXED_ARRAY_TYPE",
|
||||
188: "BLOCK_CONTEXT_TYPE",
|
||||
189: "CATCH_CONTEXT_TYPE",
|
||||
190: "DEBUG_EVALUATE_CONTEXT_TYPE",
|
||||
191: "EVAL_CONTEXT_TYPE",
|
||||
192: "FUNCTION_CONTEXT_TYPE",
|
||||
193: "MODULE_CONTEXT_TYPE",
|
||||
194: "NATIVE_CONTEXT_TYPE",
|
||||
195: "SCRIPT_CONTEXT_TYPE",
|
||||
196: "WITH_CONTEXT_TYPE",
|
||||
197: "WEAK_FIXED_ARRAY_TYPE",
|
||||
198: "TRANSITION_ARRAY_TYPE",
|
||||
199: "CALL_HANDLER_INFO_TYPE",
|
||||
200: "CELL_TYPE",
|
||||
201: "CODE_DATA_CONTAINER_TYPE",
|
||||
202: "FEEDBACK_CELL_TYPE",
|
||||
203: "FEEDBACK_VECTOR_TYPE",
|
||||
204: "LOAD_HANDLER_TYPE",
|
||||
205: "PROPERTY_ARRAY_TYPE",
|
||||
206: "PROPERTY_CELL_TYPE",
|
||||
207: "SHARED_FUNCTION_INFO_TYPE",
|
||||
208: "SMALL_ORDERED_HASH_MAP_TYPE",
|
||||
209: "SMALL_ORDERED_HASH_SET_TYPE",
|
||||
210: "STORE_HANDLER_TYPE",
|
||||
211: "WEAK_CELL_TYPE",
|
||||
212: "WEAK_ARRAY_LIST_TYPE",
|
||||
1024: "JS_PROXY_TYPE",
|
||||
1025: "JS_GLOBAL_OBJECT_TYPE",
|
||||
@ -178,57 +178,57 @@ KNOWN_MAPS = {
|
||||
("MAP_SPACE", 0x02781): (128, "SymbolMap"),
|
||||
("MAP_SPACE", 0x027d9): (72, "OneByteStringMap"),
|
||||
("MAP_SPACE", 0x02831): (187, "ScopeInfoMap"),
|
||||
("MAP_SPACE", 0x02889): (206, "SharedFunctionInfoMap"),
|
||||
("MAP_SPACE", 0x02889): (207, "SharedFunctionInfoMap"),
|
||||
("MAP_SPACE", 0x028e1): (133, "CodeMap"),
|
||||
("MAP_SPACE", 0x02939): (193, "FunctionContextMap"),
|
||||
("MAP_SPACE", 0x02991): (199, "CellMap"),
|
||||
("MAP_SPACE", 0x029e9): (210, "WeakCellMap"),
|
||||
("MAP_SPACE", 0x02a41): (205, "GlobalPropertyCellMap"),
|
||||
("MAP_SPACE", 0x02939): (192, "FunctionContextMap"),
|
||||
("MAP_SPACE", 0x02991): (200, "CellMap"),
|
||||
("MAP_SPACE", 0x029e9): (211, "WeakCellMap"),
|
||||
("MAP_SPACE", 0x02a41): (206, "GlobalPropertyCellMap"),
|
||||
("MAP_SPACE", 0x02a99): (135, "ForeignMap"),
|
||||
("MAP_SPACE", 0x02af1): (188, "TransitionArrayMap"),
|
||||
("MAP_SPACE", 0x02b49): (202, "FeedbackVectorMap"),
|
||||
("MAP_SPACE", 0x02af1): (198, "TransitionArrayMap"),
|
||||
("MAP_SPACE", 0x02b49): (203, "FeedbackVectorMap"),
|
||||
("MAP_SPACE", 0x02ba1): (131, "ArgumentsMarkerMap"),
|
||||
("MAP_SPACE", 0x02bf9): (131, "ExceptionMap"),
|
||||
("MAP_SPACE", 0x02c51): (131, "TerminationExceptionMap"),
|
||||
("MAP_SPACE", 0x02ca9): (131, "OptimizedOutMap"),
|
||||
("MAP_SPACE", 0x02d01): (131, "StaleRegisterMap"),
|
||||
("MAP_SPACE", 0x02d59): (195, "NativeContextMap"),
|
||||
("MAP_SPACE", 0x02db1): (194, "ModuleContextMap"),
|
||||
("MAP_SPACE", 0x02e09): (192, "EvalContextMap"),
|
||||
("MAP_SPACE", 0x02e61): (196, "ScriptContextMap"),
|
||||
("MAP_SPACE", 0x02eb9): (189, "BlockContextMap"),
|
||||
("MAP_SPACE", 0x02f11): (190, "CatchContextMap"),
|
||||
("MAP_SPACE", 0x02f69): (197, "WithContextMap"),
|
||||
("MAP_SPACE", 0x02fc1): (191, "DebugEvaluateContextMap"),
|
||||
("MAP_SPACE", 0x02d59): (194, "NativeContextMap"),
|
||||
("MAP_SPACE", 0x02db1): (193, "ModuleContextMap"),
|
||||
("MAP_SPACE", 0x02e09): (191, "EvalContextMap"),
|
||||
("MAP_SPACE", 0x02e61): (195, "ScriptContextMap"),
|
||||
("MAP_SPACE", 0x02eb9): (188, "BlockContextMap"),
|
||||
("MAP_SPACE", 0x02f11): (189, "CatchContextMap"),
|
||||
("MAP_SPACE", 0x02f69): (196, "WithContextMap"),
|
||||
("MAP_SPACE", 0x02fc1): (190, "DebugEvaluateContextMap"),
|
||||
("MAP_SPACE", 0x03019): (183, "ScriptContextTableMap"),
|
||||
("MAP_SPACE", 0x03071): (151, "FeedbackMetadataArrayMap"),
|
||||
("MAP_SPACE", 0x030c9): (183, "ArrayListMap"),
|
||||
("MAP_SPACE", 0x03121): (130, "BigIntMap"),
|
||||
("MAP_SPACE", 0x03179): (184, "BoilerplateDescriptionMap"),
|
||||
("MAP_SPACE", 0x031d1): (137, "BytecodeArrayMap"),
|
||||
("MAP_SPACE", 0x03229): (200, "CodeDataContainerMap"),
|
||||
("MAP_SPACE", 0x03229): (201, "CodeDataContainerMap"),
|
||||
("MAP_SPACE", 0x03281): (1057, "ExternalMap"),
|
||||
("MAP_SPACE", 0x032d9): (150, "FixedDoubleArrayMap"),
|
||||
("MAP_SPACE", 0x03331): (186, "GlobalDictionaryMap"),
|
||||
("MAP_SPACE", 0x03389): (201, "ManyClosuresCellMap"),
|
||||
("MAP_SPACE", 0x03389): (202, "ManyClosuresCellMap"),
|
||||
("MAP_SPACE", 0x033e1): (1072, "JSMessageObjectMap"),
|
||||
("MAP_SPACE", 0x03439): (183, "ModuleInfoMap"),
|
||||
("MAP_SPACE", 0x03491): (134, "MutableHeapNumberMap"),
|
||||
("MAP_SPACE", 0x034e9): (186, "NameDictionaryMap"),
|
||||
("MAP_SPACE", 0x03541): (201, "NoClosuresCellMap"),
|
||||
("MAP_SPACE", 0x03541): (202, "NoClosuresCellMap"),
|
||||
("MAP_SPACE", 0x03599): (186, "NumberDictionaryMap"),
|
||||
("MAP_SPACE", 0x035f1): (201, "OneClosureCellMap"),
|
||||
("MAP_SPACE", 0x035f1): (202, "OneClosureCellMap"),
|
||||
("MAP_SPACE", 0x03649): (186, "OrderedHashMapMap"),
|
||||
("MAP_SPACE", 0x036a1): (186, "OrderedHashSetMap"),
|
||||
("MAP_SPACE", 0x036f9): (204, "PropertyArrayMap"),
|
||||
("MAP_SPACE", 0x03751): (198, "SideEffectCallHandlerInfoMap"),
|
||||
("MAP_SPACE", 0x037a9): (198, "SideEffectFreeCallHandlerInfoMap"),
|
||||
("MAP_SPACE", 0x036f9): (205, "PropertyArrayMap"),
|
||||
("MAP_SPACE", 0x03751): (199, "SideEffectCallHandlerInfoMap"),
|
||||
("MAP_SPACE", 0x037a9): (199, "SideEffectFreeCallHandlerInfoMap"),
|
||||
("MAP_SPACE", 0x03801): (186, "SimpleNumberDictionaryMap"),
|
||||
("MAP_SPACE", 0x03859): (183, "SloppyArgumentsElementsMap"),
|
||||
("MAP_SPACE", 0x038b1): (207, "SmallOrderedHashMapMap"),
|
||||
("MAP_SPACE", 0x03909): (208, "SmallOrderedHashSetMap"),
|
||||
("MAP_SPACE", 0x038b1): (208, "SmallOrderedHashMapMap"),
|
||||
("MAP_SPACE", 0x03909): (209, "SmallOrderedHashSetMap"),
|
||||
("MAP_SPACE", 0x03961): (186, "StringTableMap"),
|
||||
("MAP_SPACE", 0x039b9): (211, "WeakFixedArrayMap"),
|
||||
("MAP_SPACE", 0x039b9): (197, "WeakFixedArrayMap"),
|
||||
("MAP_SPACE", 0x03a11): (212, "WeakArrayListMap"),
|
||||
("MAP_SPACE", 0x03a69): (106, "NativeSourceStringMap"),
|
||||
("MAP_SPACE", 0x03ac1): (64, "StringMap"),
|
||||
|
Loading…
Reference in New Issue
Block a user