Commit 40a3e6dc authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[runtime] Move validity cell from PrototypeInfo to Map.

This is a first step towards using Maps as store transition handlers.
It is expected for this CL to noticeably regress memory consumption
but most of it should be recovered by the next CL.

Bug: v8:5988
Change-Id: Ic2e301f9ccebc36e699383ded8c8cd284a906ce1
Reviewed-on: https://chromium-review.googlesource.com/928646
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51663}
parent 70222a9d
...@@ -102,7 +102,6 @@ Handle<PrototypeInfo> Factory::NewPrototypeInfo() { ...@@ -102,7 +102,6 @@ Handle<PrototypeInfo> Factory::NewPrototypeInfo() {
Handle<PrototypeInfo>::cast(NewStruct(PROTOTYPE_INFO_TYPE, TENURED)); Handle<PrototypeInfo>::cast(NewStruct(PROTOTYPE_INFO_TYPE, TENURED));
result->set_prototype_users(WeakFixedArray::Empty()); result->set_prototype_users(WeakFixedArray::Empty());
result->set_registry_slot(PrototypeInfo::UNREGISTERED); result->set_registry_slot(PrototypeInfo::UNREGISTERED);
result->set_validity_cell(Smi::FromInt(Map::kPrototypeChainValid));
result->set_bit_field(0); result->set_bit_field(0);
return result; return result;
} }
......
...@@ -2472,6 +2472,7 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type, ...@@ -2472,6 +2472,7 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
Map::ConstructionCounterBits::encode(Map::kNoSlackTracking); Map::ConstructionCounterBits::encode(Map::kNoSlackTracking);
map->set_bit_field3(bit_field3); map->set_bit_field3(bit_field3);
map->set_weak_cell_cache(Smi::kZero); map->set_weak_cell_cache(Smi::kZero);
map->set_prototype_validity_cell(Smi::kZero);
map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND); map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
return map; return map;
} }
...@@ -2507,6 +2508,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type, ...@@ -2507,6 +2508,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
map->set_dependent_code(DependentCode::cast(empty_fixed_array()), map->set_dependent_code(DependentCode::cast(empty_fixed_array()),
SKIP_WRITE_BARRIER); SKIP_WRITE_BARRIER);
map->set_weak_cell_cache(Smi::kZero); map->set_weak_cell_cache(Smi::kZero);
map->set_prototype_validity_cell(Smi::kZero);
map->set_raw_transitions(Smi::kZero); map->set_raw_transitions(Smi::kZero);
map->SetInObjectUnusedPropertyFields(inobject_properties); map->SetInObjectUnusedPropertyFields(inobject_properties);
map->set_instance_descriptors(empty_descriptor_array()); map->set_instance_descriptors(empty_descriptor_array());
......
...@@ -485,6 +485,8 @@ void Map::MapVerify() { ...@@ -485,6 +485,8 @@ void Map::MapVerify() {
DCHECK(prototype_info() == Smi::kZero || DCHECK(prototype_info() == Smi::kZero ||
prototype_info()->IsPrototypeInfo()); prototype_info()->IsPrototypeInfo());
} }
CHECK(prototype_validity_cell()->IsSmi() ||
prototype_validity_cell()->IsCell());
} }
...@@ -1400,7 +1402,6 @@ void PrototypeInfo::PrototypeInfoVerify() { ...@@ -1400,7 +1402,6 @@ void PrototypeInfo::PrototypeInfoVerify() {
} else { } else {
CHECK(prototype_users()->IsSmi()); CHECK(prototype_users()->IsSmi());
} }
CHECK(validity_cell()->IsSmi() || validity_cell()->IsCell());
} }
void Tuple2::Tuple2Verify() { void Tuple2::Tuple2Verify() {
......
...@@ -2342,7 +2342,6 @@ ACCESSORS(PrototypeInfo, weak_cell, Object, kWeakCellOffset) ...@@ -2342,7 +2342,6 @@ ACCESSORS(PrototypeInfo, weak_cell, Object, kWeakCellOffset)
ACCESSORS(PrototypeInfo, prototype_users, Object, kPrototypeUsersOffset) ACCESSORS(PrototypeInfo, prototype_users, Object, kPrototypeUsersOffset)
ACCESSORS(PrototypeInfo, object_create_map, Object, kObjectCreateMap) ACCESSORS(PrototypeInfo, object_create_map, Object, kObjectCreateMap)
SMI_ACCESSORS(PrototypeInfo, registry_slot, kRegistrySlotOffset) SMI_ACCESSORS(PrototypeInfo, registry_slot, kRegistrySlotOffset)
ACCESSORS(PrototypeInfo, validity_cell, Object, kValidityCellOffset)
SMI_ACCESSORS(PrototypeInfo, bit_field, kBitFieldOffset) SMI_ACCESSORS(PrototypeInfo, bit_field, kBitFieldOffset)
BOOL_ACCESSORS(PrototypeInfo, bit_field, should_be_fast_map, kShouldBeFastBit) BOOL_ACCESSORS(PrototypeInfo, bit_field, should_be_fast_map, kShouldBeFastBit)
......
...@@ -626,6 +626,7 @@ void Map::MapPrint(std::ostream& os) { // NOLINT ...@@ -626,6 +626,7 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
} else { } else {
os << "\n - back pointer: " << Brief(GetBackPointer()); os << "\n - back pointer: " << Brief(GetBackPointer());
} }
os << "\n - prototype_validity cell: " << Brief(prototype_validity_cell());
os << "\n - instance descriptors " << (owns_descriptors() ? "(own) " : "") os << "\n - instance descriptors " << (owns_descriptors() ? "(own) " : "")
<< "#" << NumberOfOwnDescriptors() << ": " << "#" << NumberOfOwnDescriptors() << ": "
<< Brief(instance_descriptors()); << Brief(instance_descriptors());
...@@ -1443,7 +1444,6 @@ void PrototypeInfo::PrototypeInfoPrint(std::ostream& os) { // NOLINT ...@@ -1443,7 +1444,6 @@ void PrototypeInfo::PrototypeInfoPrint(std::ostream& os) { // NOLINT
os << "\n - weak cell: " << Brief(weak_cell()); os << "\n - weak cell: " << Brief(weak_cell());
os << "\n - prototype users: " << Brief(prototype_users()); os << "\n - prototype users: " << Brief(prototype_users());
os << "\n - registry slot: " << registry_slot(); os << "\n - registry slot: " << registry_slot();
os << "\n - validity cell: " << Brief(validity_cell());
os << "\n - object create map: " << Brief(object_create_map()); os << "\n - object create map: " << Brief(object_create_map());
os << "\n - should_be_fast_map: " << should_be_fast_map(); os << "\n - should_be_fast_map: " << should_be_fast_map();
os << "\n"; os << "\n";
......
...@@ -12432,28 +12432,26 @@ namespace { ...@@ -12432,28 +12432,26 @@ namespace {
// This function must be kept in sync with // This function must be kept in sync with
// AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks // AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
// before jumping here. // before jumping here.
PrototypeInfo* InvalidateOnePrototypeValidityCellInternal(Map* map) { void InvalidateOnePrototypeValidityCellInternal(Map* map) {
DCHECK(map->is_prototype_map()); DCHECK(map->is_prototype_map());
if (FLAG_trace_prototype_users) { if (FLAG_trace_prototype_users) {
PrintF("Invalidating prototype map %p 's cell\n", PrintF("Invalidating prototype map %p 's cell\n",
reinterpret_cast<void*>(map)); reinterpret_cast<void*>(map));
} }
Object* maybe_proto_info = map->prototype_info(); Object* maybe_cell = map->prototype_validity_cell();
if (!maybe_proto_info->IsPrototypeInfo()) return nullptr;
PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
Object* maybe_cell = proto_info->validity_cell();
if (maybe_cell->IsCell()) { if (maybe_cell->IsCell()) {
// Just set the value; the cell will be replaced lazily. // Just set the value; the cell will be replaced lazily.
Cell* cell = Cell::cast(maybe_cell); Cell* cell = Cell::cast(maybe_cell);
cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
} }
return proto_info;
} }
void InvalidatePrototypeChainsInternal(Map* map) { void InvalidatePrototypeChainsInternal(Map* map) {
PrototypeInfo* proto_info = InvalidateOnePrototypeValidityCellInternal(map); InvalidateOnePrototypeValidityCellInternal(map);
if (proto_info == nullptr) return;
Object* maybe_proto_info = map->prototype_info();
if (!maybe_proto_info->IsPrototypeInfo()) return;
PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
WeakFixedArray::Iterator iterator(proto_info->prototype_users()); WeakFixedArray::Iterator iterator(proto_info->prototype_users());
// For now, only maps register themselves as users. // For now, only maps register themselves as users.
Map* user; Map* user;
...@@ -12544,9 +12542,8 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, ...@@ -12544,9 +12542,8 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
// will be invalidated when necessary. // will be invalidated when necessary.
JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
isolate); isolate);
Handle<PrototypeInfo> proto_info =
GetOrCreatePrototypeInfo(prototype, isolate); Object* maybe_cell = prototype->map()->prototype_validity_cell();
Object* maybe_cell = proto_info->validity_cell();
// Return existing cell if it's still valid. // Return existing cell if it's still valid.
if (maybe_cell->IsCell()) { if (maybe_cell->IsCell()) {
Handle<Cell> cell(Cell::cast(maybe_cell), isolate); Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
...@@ -12557,21 +12554,17 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, ...@@ -12557,21 +12554,17 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
// Otherwise create a new cell. // Otherwise create a new cell.
Handle<Cell> cell = isolate->factory()->NewCell( Handle<Cell> cell = isolate->factory()->NewCell(
handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
proto_info->set_validity_cell(*cell); prototype->map()->set_prototype_validity_cell(*cell);
return cell; return cell;
} }
// static // static
bool Map::IsPrototypeChainInvalidated(Map* map) { bool Map::IsPrototypeChainInvalidated(Map* map) {
DCHECK(map->is_prototype_map()); DCHECK(map->is_prototype_map());
Object* maybe_proto_info = map->prototype_info(); Object* maybe_cell = map->prototype_validity_cell();
if (maybe_proto_info->IsPrototypeInfo()) { if (maybe_cell->IsCell()) {
PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); Cell* cell = Cell::cast(maybe_cell);
Object* maybe_cell = proto_info->validity_cell(); return cell->value() != Smi::FromInt(Map::kPrototypeChainValid);
if (maybe_cell->IsCell()) {
Cell* cell = Cell::cast(maybe_cell);
return cell->value() == Smi::FromInt(Map::kPrototypeChainInvalid);
}
} }
return true; return true;
} }
......
...@@ -2934,13 +2934,7 @@ class PrototypeInfo : public Struct { ...@@ -2934,13 +2934,7 @@ class PrototypeInfo : public Struct {
// is stored. Returns UNREGISTERED if this prototype has not been registered. // is stored. Returns UNREGISTERED if this prototype has not been registered.
inline int registry_slot() const; inline int registry_slot() const;
inline void set_registry_slot(int slot); inline void set_registry_slot(int slot);
// [validity_cell]: Cell containing the validity bit for prototype chains
// going through this object, or Smi(0) if uninitialized.
// When a prototype object changes its map, then both its own validity cell
// and those of all "downstream" prototypes are invalidated; handlers for a
// given receiver embed the currently valid cell for that receiver's prototype
// during their compilation and check it on execution.
DECL_ACCESSORS(validity_cell, Object)
// [bit_field] // [bit_field]
inline int bit_field() const; inline int bit_field() const;
inline void set_bit_field(int bit_field); inline void set_bit_field(int bit_field);
......
...@@ -660,6 +660,7 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) { ...@@ -660,6 +660,7 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset) ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
ACCESSORS(Map, weak_cell_cache, Object, kWeakCellCacheOffset) ACCESSORS(Map, weak_cell_cache, Object, kWeakCellCacheOffset)
ACCESSORS(Map, prototype_validity_cell, Object, kPrototypeValidityCellOffset)
ACCESSORS(Map, constructor_or_backpointer, Object, ACCESSORS(Map, constructor_or_backpointer, Object,
kConstructorOrBackPointerOffset) kConstructorOrBackPointerOffset)
......
...@@ -559,6 +559,20 @@ class Map : public HeapObject { ...@@ -559,6 +559,20 @@ class Map : public HeapObject {
// [weak cell cache]: cache that stores a weak cell pointing to this map. // [weak cell cache]: cache that stores a weak cell pointing to this map.
DECL_ACCESSORS(weak_cell_cache, Object) DECL_ACCESSORS(weak_cell_cache, Object)
// [prototype_validity_cell]: Cell containing the validity bit for prototype
// chains or Smi(0) if uninitialized.
// The meaning of this validity cell is different for prototype maps and
// non-prototype maps.
// For prototype maps the validity bit "guards" modifications of prototype
// chains going through this object. When a prototype object changes, both its
// own validity cell and those of all "downstream" prototypes are invalidated;
// handlers for a given receiver embed the currently valid cell for that
// receiver's prototype during their creation and check it on execution.
// For non-prototype maps which are used as transitioning store handlers this
// field contains the validity cell which guards modifications of this map's
// prototype.
DECL_ACCESSORS(prototype_validity_cell, Object)
inline PropertyDetails GetLastDescriptorDetails() const; inline PropertyDetails GetLastDescriptorDetails() const;
inline int LastAdded() const; inline int LastAdded() const;
...@@ -773,6 +787,7 @@ class Map : public HeapObject { ...@@ -773,6 +787,7 @@ class Map : public HeapObject {
V(kLayoutDescriptorOffset, FLAG_unbox_double_fields ? kPointerSize : 0) \ V(kLayoutDescriptorOffset, FLAG_unbox_double_fields ? kPointerSize : 0) \
V(kDependentCodeOffset, kPointerSize) \ V(kDependentCodeOffset, kPointerSize) \
V(kWeakCellCacheOffset, kPointerSize) \ V(kWeakCellCacheOffset, kPointerSize) \
V(kPrototypeValidityCellOffset, kPointerSize) \
V(kPointerFieldsEndOffset, 0) \ V(kPointerFieldsEndOffset, 0) \
/* Total size. */ \ /* Total size. */ \
V(kSize, 0) V(kSize, 0)
......
This diff is collapsed.
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