Introduce instance type for transition arrays.
The motivation is to allow specialized marking visitor for transition arrays and collect all transition array in a list for post-processing in ClearNonLiveReferences. BUG=chromium:554488 LOG=NO Review URL: https://codereview.chromium.org/1480873003 Cr-Commit-Position: refs/heads/master@{#32396}
This commit is contained in:
parent
b7995d4bb4
commit
026095a3c7
@ -7092,7 +7092,7 @@ class Internals {
|
||||
static const int kNodeIsPartiallyDependentShift = 4;
|
||||
static const int kNodeIsActiveShift = 4;
|
||||
|
||||
static const int kJSObjectType = 0xb7;
|
||||
static const int kJSObjectType = 0xb8;
|
||||
static const int kFirstNonstringType = 0x80;
|
||||
static const int kOddballType = 0x83;
|
||||
static const int kForeignType = 0x87;
|
||||
|
@ -966,6 +966,13 @@ Handle<WeakCell> Factory::NewWeakCell(Handle<HeapObject> value) {
|
||||
}
|
||||
|
||||
|
||||
Handle<TransitionArray> Factory::NewTransitionArray(int capacity) {
|
||||
CALL_HEAP_FUNCTION(isolate(),
|
||||
isolate()->heap()->AllocateTransitionArray(capacity),
|
||||
TransitionArray);
|
||||
}
|
||||
|
||||
|
||||
Handle<AllocationSite> Factory::NewAllocationSite() {
|
||||
Handle<Map> map = allocation_site_map();
|
||||
Handle<AllocationSite> site = New<AllocationSite>(map, OLD_SPACE);
|
||||
|
@ -295,6 +295,8 @@ class Factory final {
|
||||
|
||||
Handle<WeakCell> NewWeakCell(Handle<HeapObject> value);
|
||||
|
||||
Handle<TransitionArray> NewTransitionArray(int capacity);
|
||||
|
||||
// Allocate a tenured AllocationSite. It's payload is null.
|
||||
Handle<AllocationSite> NewAllocationSite();
|
||||
|
||||
|
@ -180,6 +180,7 @@ Heap::Heap()
|
||||
set_allocation_sites_list(Smi::FromInt(0));
|
||||
set_encountered_weak_collections(Smi::FromInt(0));
|
||||
set_encountered_weak_cells(Smi::FromInt(0));
|
||||
set_encountered_transition_arrays(Smi::FromInt(0));
|
||||
// Put a dummy entry in the remembered pages so we can find the list the
|
||||
// minidump even if there are no real unmapped pages.
|
||||
RememberUnmappedPage(NULL, false);
|
||||
@ -2333,6 +2334,7 @@ bool Heap::CreateInitialMaps() {
|
||||
ALLOCATE_MAP(FILLER_TYPE, kPointerSize, one_pointer_filler)
|
||||
ALLOCATE_MAP(FILLER_TYPE, 2 * kPointerSize, two_pointer_filler)
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(TRANSITION_ARRAY_TYPE, transition_array)
|
||||
|
||||
for (unsigned i = 0; i < arraysize(struct_table); i++) {
|
||||
const StructTable& entry = struct_table[i];
|
||||
@ -2494,6 +2496,21 @@ AllocationResult Heap::AllocateWeakCell(HeapObject* value) {
|
||||
}
|
||||
|
||||
|
||||
AllocationResult Heap::AllocateTransitionArray(int capacity) {
|
||||
DCHECK(capacity > 0);
|
||||
HeapObject* raw_array = nullptr;
|
||||
{
|
||||
AllocationResult allocation = AllocateRawFixedArray(capacity, TENURED);
|
||||
if (!allocation.To(&raw_array)) return allocation;
|
||||
}
|
||||
raw_array->set_map_no_write_barrier(transition_array_map());
|
||||
TransitionArray* array = TransitionArray::cast(raw_array);
|
||||
array->set_length(capacity);
|
||||
MemsetPointer(array->data_start(), undefined_value(), capacity);
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
void Heap::CreateApiObjects() {
|
||||
HandleScope scope(isolate());
|
||||
Factory* factory = isolate()->factory();
|
||||
|
@ -61,6 +61,7 @@ namespace internal {
|
||||
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||
V(Map, weak_cell_map, WeakCellMap) \
|
||||
V(Map, transition_array_map, TransitionArrayMap) \
|
||||
V(Map, one_byte_string_map, OneByteStringMap) \
|
||||
V(Map, one_byte_internalized_string_map, OneByteInternalizedStringMap) \
|
||||
V(Map, function_context_map, FunctionContextMap) \
|
||||
@ -423,6 +424,7 @@ namespace internal {
|
||||
V(FixedCOWArrayMap) \
|
||||
V(FixedDoubleArrayMap) \
|
||||
V(WeakCellMap) \
|
||||
V(TransitionArrayMap) \
|
||||
V(NoInterceptorResultSentinel) \
|
||||
V(HashTableMap) \
|
||||
V(OrderedHashTableMap) \
|
||||
@ -882,6 +884,13 @@ class Heap {
|
||||
}
|
||||
Object* encountered_weak_cells() const { return encountered_weak_cells_; }
|
||||
|
||||
void set_encountered_transition_arrays(Object* transition_array) {
|
||||
encountered_transition_arrays_ = transition_array;
|
||||
}
|
||||
Object* encountered_transition_arrays() const {
|
||||
return encountered_transition_arrays_;
|
||||
}
|
||||
|
||||
// Number of mark-sweeps.
|
||||
int ms_count() const { return ms_count_; }
|
||||
|
||||
@ -2095,6 +2104,8 @@ class Heap {
|
||||
|
||||
MUST_USE_RESULT AllocationResult AllocateWeakCell(HeapObject* value);
|
||||
|
||||
MUST_USE_RESULT AllocationResult AllocateTransitionArray(int capacity);
|
||||
|
||||
// Allocates a new utility object in the old generation.
|
||||
MUST_USE_RESULT AllocationResult AllocateStruct(InstanceType type);
|
||||
|
||||
@ -2221,6 +2232,8 @@ class Heap {
|
||||
|
||||
Object* encountered_weak_cells_;
|
||||
|
||||
Object* encountered_transition_arrays_;
|
||||
|
||||
StoreBufferRebuilder store_buffer_rebuilder_;
|
||||
|
||||
List<GCCallbackPair> gc_epilogue_callbacks_;
|
||||
|
@ -831,6 +831,7 @@ void MarkCompactCollector::Prepare() {
|
||||
ClearMarkbits();
|
||||
AbortWeakCollections();
|
||||
AbortWeakCells();
|
||||
AbortTransitionArrays();
|
||||
AbortCompaction();
|
||||
was_marked_incrementally_ = false;
|
||||
}
|
||||
@ -2329,14 +2330,15 @@ void MarkCompactCollector::ProcessWeakReferences() {
|
||||
ClearNonLiveReferences();
|
||||
|
||||
ClearWeakCollections();
|
||||
|
||||
heap_->set_encountered_weak_cells(Smi::FromInt(0));
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::ClearNonLiveReferences() {
|
||||
GCTracer::Scope gc_scope(heap()->tracer(),
|
||||
GCTracer::Scope::MC_NONLIVEREFERENCES);
|
||||
|
||||
ProcessAndClearTransitionArrays();
|
||||
|
||||
// Iterate over the map space, setting map transitions that go from
|
||||
// a marked map to an unmarked map to null transitions. This action
|
||||
// is carried out only on maps of JSObjects and related subtypes.
|
||||
@ -2655,6 +2657,31 @@ void MarkCompactCollector::AbortWeakCells() {
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::ProcessAndClearTransitionArrays() {
|
||||
HeapObject* undefined = heap()->undefined_value();
|
||||
Object* obj = heap()->encountered_transition_arrays();
|
||||
while (obj != Smi::FromInt(0)) {
|
||||
TransitionArray* array = TransitionArray::cast(obj);
|
||||
// TODO(ulan): move logic from ClearMapTransitions here.
|
||||
obj = array->next_link();
|
||||
array->set_next_link(undefined, SKIP_WRITE_BARRIER);
|
||||
}
|
||||
heap()->set_encountered_transition_arrays(Smi::FromInt(0));
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::AbortTransitionArrays() {
|
||||
HeapObject* undefined = heap()->undefined_value();
|
||||
Object* obj = heap()->encountered_transition_arrays();
|
||||
while (obj != Smi::FromInt(0)) {
|
||||
TransitionArray* array = TransitionArray::cast(obj);
|
||||
obj = array->next_link();
|
||||
array->set_next_link(undefined, SKIP_WRITE_BARRIER);
|
||||
}
|
||||
heap()->set_encountered_transition_arrays(Smi::FromInt(0));
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::RecordMigratedSlot(
|
||||
Object* value, Address slot, SlotsBuffer** evacuation_slots_buffer) {
|
||||
// When parallel compaction is in progress, store and slots buffer entries
|
||||
|
@ -684,6 +684,9 @@ class MarkCompactCollector {
|
||||
void ProcessAndClearWeakCells();
|
||||
void AbortWeakCells();
|
||||
|
||||
void ProcessAndClearTransitionArrays();
|
||||
void AbortTransitionArrays();
|
||||
|
||||
// After all reachable objects have been marked, those entries within
|
||||
// optimized code maps that became unreachable are removed, potentially
|
||||
// trimming or clearing out the entire optimized code map.
|
||||
|
@ -186,12 +186,6 @@ void ObjectStatsVisitor::Visit<ObjectStatsVisitor::kVisitMap>(Map* map,
|
||||
heap->object_stats_->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE,
|
||||
fixed_array_size);
|
||||
}
|
||||
if (TransitionArray::IsFullTransitionArray(map_obj->raw_transitions())) {
|
||||
int fixed_array_size =
|
||||
TransitionArray::cast(map_obj->raw_transitions())->Size();
|
||||
heap->object_stats_->RecordFixedArraySubTypeStats(TRANSITION_ARRAY_SUB_TYPE,
|
||||
fixed_array_size);
|
||||
}
|
||||
if (map_obj->has_code_cache()) {
|
||||
CodeCache* cache = CodeCache::cast(map_obj->code_cache());
|
||||
heap->object_stats_->RecordFixedArraySubTypeStats(
|
||||
|
@ -179,6 +179,8 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() {
|
||||
|
||||
table_.Register(kVisitWeakCell, &VisitWeakCell);
|
||||
|
||||
table_.Register(kVisitTransitionArray, &VisitTransitionArray);
|
||||
|
||||
table_.template RegisterSpecializations<DataObjectVisitor, kVisitDataObject,
|
||||
kVisitDataObjectGeneric>();
|
||||
|
||||
@ -341,6 +343,25 @@ void StaticMarkingVisitor<StaticVisitor>::VisitWeakCell(Map* map,
|
||||
}
|
||||
|
||||
|
||||
template <typename StaticVisitor>
|
||||
void StaticMarkingVisitor<StaticVisitor>::VisitTransitionArray(
|
||||
Map* map, HeapObject* object) {
|
||||
typedef FlexibleBodyVisitor<StaticVisitor, TransitionArray::BodyDescriptor,
|
||||
int> TransitionArrayBodyVisitor;
|
||||
TransitionArray* array = TransitionArray::cast(object);
|
||||
// Enqueue the array in linked list of encountered transition arrays if it is
|
||||
// not already in the list.
|
||||
if (array->next_link()->IsUndefined()) {
|
||||
Heap* heap = map->GetHeap();
|
||||
array->set_next_link(heap->encountered_transition_arrays(),
|
||||
UPDATE_WEAK_WRITE_BARRIER);
|
||||
heap->set_encountered_transition_arrays(array);
|
||||
}
|
||||
// TODO(ulan): Move MarkTransitionArray logic here.
|
||||
TransitionArrayBodyVisitor::Visit(map, object);
|
||||
}
|
||||
|
||||
|
||||
template <typename StaticVisitor>
|
||||
void StaticMarkingVisitor<StaticVisitor>::VisitAllocationSite(
|
||||
Map* map, HeapObject* object) {
|
||||
|
@ -79,6 +79,9 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
case WEAK_CELL_TYPE:
|
||||
return kVisitWeakCell;
|
||||
|
||||
case TRANSITION_ARRAY_TYPE:
|
||||
return kVisitTransitionArray;
|
||||
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
case JS_WEAK_SET_TYPE:
|
||||
return kVisitJSWeakCollection;
|
||||
|
@ -76,6 +76,7 @@ class StaticVisitorBase : public AllStatic {
|
||||
V(Cell) \
|
||||
V(PropertyCell) \
|
||||
V(WeakCell) \
|
||||
V(TransitionArray) \
|
||||
V(SharedFunctionInfo) \
|
||||
V(JSFunction) \
|
||||
V(JSWeakCollection) \
|
||||
@ -347,6 +348,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
|
||||
|
||||
INLINE(static void VisitPropertyCell(Map* map, HeapObject* object));
|
||||
INLINE(static void VisitWeakCell(Map* map, HeapObject* object));
|
||||
INLINE(static void VisitTransitionArray(Map* map, HeapObject* object));
|
||||
INLINE(static void VisitCodeEntry(Heap* heap, HeapObject* object,
|
||||
Address entry_address));
|
||||
INLINE(static void VisitEmbeddedPointer(Heap* heap, RelocInfo* rinfo));
|
||||
|
@ -448,6 +448,8 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) {
|
||||
return Op::template apply<FixedArray::BodyDescriptor>(p1, p2, p3);
|
||||
case FIXED_DOUBLE_ARRAY_TYPE:
|
||||
return ReturnType();
|
||||
case TRANSITION_ARRAY_TYPE:
|
||||
return Op::template apply<TransitionArray::BodyDescriptor>(p1, p2, p3);
|
||||
case JS_OBJECT_TYPE:
|
||||
case JS_PROMISE_TYPE:
|
||||
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
||||
|
@ -76,6 +76,9 @@ void HeapObject::HeapObjectVerify() {
|
||||
case BYTECODE_ARRAY_TYPE:
|
||||
BytecodeArray::cast(this)->BytecodeArrayVerify();
|
||||
break;
|
||||
case TRANSITION_ARRAY_TYPE:
|
||||
TransitionArray::cast(this)->TransitionArrayVerify();
|
||||
break;
|
||||
case FREE_SPACE_TYPE:
|
||||
FreeSpace::cast(this)->FreeSpaceVerify();
|
||||
break;
|
||||
@ -407,6 +410,17 @@ void FixedDoubleArray::FixedDoubleArrayVerify() {
|
||||
}
|
||||
|
||||
|
||||
void TransitionArray::TransitionArrayVerify() {
|
||||
for (int i = 0; i < length(); i++) {
|
||||
Object* e = get(i);
|
||||
VerifyPointer(e);
|
||||
}
|
||||
CHECK_LE(LengthFor(number_of_transitions()), length());
|
||||
CHECK(next_link()->IsUndefined() || next_link()->IsSmi() ||
|
||||
next_link()->IsTransitionArray());
|
||||
}
|
||||
|
||||
|
||||
void JSGeneratorObject::JSGeneratorObjectVerify() {
|
||||
// In an expression like "new g()", there can be a point where a generator
|
||||
// object is allocated but its fields are all undefined, as it hasn't yet been
|
||||
|
@ -134,6 +134,14 @@ bool Object::IsFixedArrayBase() const {
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsFixedArray() const {
|
||||
if (!IsHeapObject()) return false;
|
||||
InstanceType instance_type = HeapObject::cast(this)->map()->instance_type();
|
||||
return instance_type == FIXED_ARRAY_TYPE ||
|
||||
instance_type == TRANSITION_ARRAY_TYPE;
|
||||
}
|
||||
|
||||
|
||||
// External objects are not extensible, so the map check is enough.
|
||||
bool Object::IsExternal() const {
|
||||
return Object::IsHeapObject() &&
|
||||
@ -717,9 +725,9 @@ TYPE_CHECKER(JSWeakMap, JS_WEAK_MAP_TYPE)
|
||||
TYPE_CHECKER(JSWeakSet, JS_WEAK_SET_TYPE)
|
||||
TYPE_CHECKER(JSContextExtensionObject, JS_CONTEXT_EXTENSION_OBJECT_TYPE)
|
||||
TYPE_CHECKER(Map, MAP_TYPE)
|
||||
TYPE_CHECKER(FixedArray, FIXED_ARRAY_TYPE)
|
||||
TYPE_CHECKER(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE)
|
||||
TYPE_CHECKER(WeakFixedArray, FIXED_ARRAY_TYPE)
|
||||
TYPE_CHECKER(TransitionArray, TRANSITION_ARRAY_TYPE)
|
||||
|
||||
|
||||
bool Object::IsJSWeakCollection() const {
|
||||
@ -740,11 +748,6 @@ bool Object::IsLayoutDescriptor() const {
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsTransitionArray() const {
|
||||
return IsFixedArray();
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsTypeFeedbackVector() const { return IsFixedArray(); }
|
||||
|
||||
|
||||
@ -2406,7 +2409,7 @@ void FixedArray::set(int index, Smi* value) {
|
||||
|
||||
void FixedArray::set(int index, Object* value) {
|
||||
DCHECK_NE(GetHeap()->fixed_cow_array_map(), map());
|
||||
DCHECK_EQ(FIXED_ARRAY_TYPE, map()->instance_type());
|
||||
DCHECK(IsFixedArray());
|
||||
DCHECK(index >= 0 && index < this->length());
|
||||
int offset = kHeaderSize + index * kPointerSize;
|
||||
WRITE_FIELD(this, offset, value);
|
||||
@ -4456,7 +4459,8 @@ int HeapObject::SizeFromMap(Map* map) {
|
||||
if (instance_size != kVariableSizeSentinel) return instance_size;
|
||||
// Only inline the most frequent cases.
|
||||
InstanceType instance_type = map->instance_type();
|
||||
if (instance_type == FIXED_ARRAY_TYPE) {
|
||||
if (instance_type == FIXED_ARRAY_TYPE ||
|
||||
instance_type == TRANSITION_ARRAY_TYPE) {
|
||||
return FixedArray::SizeFor(
|
||||
reinterpret_cast<FixedArray*>(this)->synchronized_length());
|
||||
}
|
||||
|
@ -76,6 +76,9 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
|
||||
case BYTECODE_ARRAY_TYPE:
|
||||
BytecodeArray::cast(this)->BytecodeArrayPrint(os);
|
||||
break;
|
||||
case TRANSITION_ARRAY_TYPE:
|
||||
TransitionArray::cast(this)->TransitionArrayPrint(os);
|
||||
break;
|
||||
case FREE_SPACE_TYPE:
|
||||
FreeSpace::cast(this)->FreeSpacePrint(os);
|
||||
break;
|
||||
@ -553,6 +556,19 @@ void FixedDoubleArray::FixedDoubleArrayPrint(std::ostream& os) { // NOLINT
|
||||
}
|
||||
|
||||
|
||||
void TransitionArray::TransitionArrayPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "TransitionArray");
|
||||
os << " - capacity: " << length();
|
||||
for (int i = 0; i < length(); i++) {
|
||||
os << "\n [" << i << "]: " << Brief(get(i));
|
||||
if (i == kNextLinkIndex) os << " (next link)";
|
||||
if (i == kPrototypeTransitionsIndex) os << " (prototype transitions)";
|
||||
if (i == kTransitionLengthIndex) os << " (number of transitions)";
|
||||
}
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackMetadata::Print() {
|
||||
OFStream os(stdout);
|
||||
TypeFeedbackMetadataPrint(os);
|
||||
|
@ -1945,6 +1945,10 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
|
||||
case BYTECODE_ARRAY_TYPE:
|
||||
os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
|
||||
break;
|
||||
case TRANSITION_ARRAY_TYPE:
|
||||
os << "<TransitionArray[" << TransitionArray::cast(this)->length()
|
||||
<< "]>";
|
||||
break;
|
||||
case FREE_SPACE_TYPE:
|
||||
os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
|
||||
break;
|
||||
|
@ -411,6 +411,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(FIXED_DOUBLE_ARRAY_TYPE) \
|
||||
V(SHARED_FUNCTION_INFO_TYPE) \
|
||||
V(WEAK_CELL_TYPE) \
|
||||
V(TRANSITION_ARRAY_TYPE) \
|
||||
\
|
||||
V(JS_MESSAGE_OBJECT_TYPE) \
|
||||
\
|
||||
@ -701,6 +702,7 @@ enum InstanceType {
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
CELL_TYPE,
|
||||
WEAK_CELL_TYPE,
|
||||
TRANSITION_ARRAY_TYPE,
|
||||
PROPERTY_CELL_TYPE,
|
||||
PROTOTYPE_INFO_TYPE,
|
||||
SLOPPY_BLOCK_WITH_EVAL_CONTEXT_EXTENSION_TYPE,
|
||||
@ -785,14 +787,13 @@ STATIC_ASSERT(FOREIGN_TYPE == Internals::kForeignType);
|
||||
V(MAP_CODE_CACHE_SUB_TYPE) \
|
||||
V(SCOPE_INFO_SUB_TYPE) \
|
||||
V(STRING_TABLE_SUB_TYPE) \
|
||||
V(DESCRIPTOR_ARRAY_SUB_TYPE) \
|
||||
V(TRANSITION_ARRAY_SUB_TYPE)
|
||||
V(DESCRIPTOR_ARRAY_SUB_TYPE)
|
||||
|
||||
enum FixedArraySubInstanceType {
|
||||
#define DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE(name) name,
|
||||
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE)
|
||||
#undef DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE
|
||||
LAST_FIXED_ARRAY_SUB_TYPE = TRANSITION_ARRAY_SUB_TYPE
|
||||
LAST_FIXED_ARRAY_SUB_TYPE = DESCRIPTOR_ARRAY_SUB_TYPE
|
||||
};
|
||||
|
||||
|
||||
@ -860,6 +861,7 @@ class StringStream;
|
||||
class TypeFeedbackInfo;
|
||||
class TypeFeedbackVector;
|
||||
class WeakCell;
|
||||
class TransitionArray;
|
||||
|
||||
// We cannot just say "class HeapType;" if it is created from a template... =8-?
|
||||
template<class> class TypeImpl;
|
||||
|
@ -17,6 +17,14 @@ TransitionArray* TransitionArray::cast(Object* object) {
|
||||
}
|
||||
|
||||
|
||||
Object* TransitionArray::next_link() { return get(kNextLinkIndex); }
|
||||
|
||||
|
||||
void TransitionArray::set_next_link(Object* next, WriteBarrierMode mode) {
|
||||
return set(kNextLinkIndex, next, mode);
|
||||
}
|
||||
|
||||
|
||||
bool TransitionArray::HasPrototypeTransitions() {
|
||||
return get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
|
||||
}
|
||||
|
@ -391,18 +391,23 @@ int TransitionArray::Capacity(Object* raw_transitions) {
|
||||
Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
|
||||
int number_of_transitions,
|
||||
int slack) {
|
||||
Handle<FixedArray> array = isolate->factory()->NewFixedArray(
|
||||
LengthFor(number_of_transitions + slack), TENURED);
|
||||
Handle<FixedArray> array = isolate->factory()->NewTransitionArray(
|
||||
LengthFor(number_of_transitions + slack));
|
||||
array->set(kNextLinkIndex, isolate->heap()->undefined_value());
|
||||
array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
|
||||
array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
|
||||
return Handle<TransitionArray>::cast(array);
|
||||
}
|
||||
|
||||
|
||||
static void ZapTransitionArray(TransitionArray* transitions) {
|
||||
MemsetPointer(transitions->data_start(),
|
||||
// static
|
||||
void TransitionArray::ZapTransitionArray(TransitionArray* transitions) {
|
||||
// Do not zap the next link that is used by GC.
|
||||
STATIC_ASSERT(kNextLinkIndex + 1 == kPrototypeTransitionsIndex);
|
||||
MemsetPointer(transitions->data_start() + kPrototypeTransitionsIndex,
|
||||
transitions->GetHeap()->the_hole_value(),
|
||||
transitions->length());
|
||||
transitions->length() - kPrototypeTransitionsIndex);
|
||||
transitions->SetNumberOfTransitions(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,8 +165,11 @@ class TransitionArray: public FixedArray {
|
||||
|
||||
static int Capacity(Object* raw_transitions);
|
||||
|
||||
// Casting.
|
||||
static inline TransitionArray* cast(Object* obj);
|
||||
inline static TransitionArray* cast(Object* object);
|
||||
|
||||
// This field should be used only by GC.
|
||||
inline void set_next_link(Object* next, WriteBarrierMode mode);
|
||||
inline Object* next_link();
|
||||
|
||||
static const int kTransitionSize = 2;
|
||||
static const int kProtoTransitionHeaderSize = 1;
|
||||
@ -180,6 +183,14 @@ class TransitionArray: public FixedArray {
|
||||
bool print_header = true); // NOLINT
|
||||
#endif
|
||||
|
||||
#ifdef OBJECT_PRINT
|
||||
void TransitionArrayPrint(std::ostream& os); // NOLINT
|
||||
#endif
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
void TransitionArrayVerify();
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsSortedNoDuplicates(int valid_entries = -1);
|
||||
static bool IsSortedNoDuplicates(Map* map);
|
||||
@ -199,9 +210,10 @@ class TransitionArray: public FixedArray {
|
||||
|
||||
private:
|
||||
// Layout for full transition arrays.
|
||||
static const int kPrototypeTransitionsIndex = 0;
|
||||
static const int kTransitionLengthIndex = 1;
|
||||
static const int kFirstIndex = 2;
|
||||
static const int kNextLinkIndex = 0;
|
||||
static const int kPrototypeTransitionsIndex = 1;
|
||||
static const int kTransitionLengthIndex = 2;
|
||||
static const int kFirstIndex = 3;
|
||||
|
||||
// Layout of map transition entries in full transition arrays.
|
||||
static const int kTransitionKey = 0;
|
||||
@ -304,6 +316,7 @@ class TransitionArray: public FixedArray {
|
||||
TransitionArray* old_transitions,
|
||||
Object* transitions);
|
||||
#endif
|
||||
static void ZapTransitionArray(TransitionArray* transitions);
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionArray);
|
||||
};
|
||||
|
@ -275,6 +275,7 @@ TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
|
||||
case FIXED_DOUBLE_ARRAY_TYPE:
|
||||
case BYTE_ARRAY_TYPE:
|
||||
case BYTECODE_ARRAY_TYPE:
|
||||
case TRANSITION_ARRAY_TYPE:
|
||||
case FOREIGN_TYPE:
|
||||
case SCRIPT_TYPE:
|
||||
case CODE_TYPE:
|
||||
|
Loading…
Reference in New Issue
Block a user