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() {
Handle<PrototypeInfo>::cast(NewStruct(PROTOTYPE_INFO_TYPE, TENURED));
result->set_prototype_users(WeakFixedArray::Empty());
result->set_registry_slot(PrototypeInfo::UNREGISTERED);
result->set_validity_cell(Smi::FromInt(Map::kPrototypeChainValid));
result->set_bit_field(0);
return result;
}
......
......@@ -2472,6 +2472,7 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
Map::ConstructionCounterBits::encode(Map::kNoSlackTracking);
map->set_bit_field3(bit_field3);
map->set_weak_cell_cache(Smi::kZero);
map->set_prototype_validity_cell(Smi::kZero);
map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
return map;
}
......@@ -2507,6 +2508,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
map->set_dependent_code(DependentCode::cast(empty_fixed_array()),
SKIP_WRITE_BARRIER);
map->set_weak_cell_cache(Smi::kZero);
map->set_prototype_validity_cell(Smi::kZero);
map->set_raw_transitions(Smi::kZero);
map->SetInObjectUnusedPropertyFields(inobject_properties);
map->set_instance_descriptors(empty_descriptor_array());
......
......@@ -485,6 +485,8 @@ void Map::MapVerify() {
DCHECK(prototype_info() == Smi::kZero ||
prototype_info()->IsPrototypeInfo());
}
CHECK(prototype_validity_cell()->IsSmi() ||
prototype_validity_cell()->IsCell());
}
......@@ -1400,7 +1402,6 @@ void PrototypeInfo::PrototypeInfoVerify() {
} else {
CHECK(prototype_users()->IsSmi());
}
CHECK(validity_cell()->IsSmi() || validity_cell()->IsCell());
}
void Tuple2::Tuple2Verify() {
......
......@@ -2342,7 +2342,6 @@ ACCESSORS(PrototypeInfo, weak_cell, Object, kWeakCellOffset)
ACCESSORS(PrototypeInfo, prototype_users, Object, kPrototypeUsersOffset)
ACCESSORS(PrototypeInfo, object_create_map, Object, kObjectCreateMap)
SMI_ACCESSORS(PrototypeInfo, registry_slot, kRegistrySlotOffset)
ACCESSORS(PrototypeInfo, validity_cell, Object, kValidityCellOffset)
SMI_ACCESSORS(PrototypeInfo, bit_field, kBitFieldOffset)
BOOL_ACCESSORS(PrototypeInfo, bit_field, should_be_fast_map, kShouldBeFastBit)
......
......@@ -626,6 +626,7 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
} else {
os << "\n - back pointer: " << Brief(GetBackPointer());
}
os << "\n - prototype_validity cell: " << Brief(prototype_validity_cell());
os << "\n - instance descriptors " << (owns_descriptors() ? "(own) " : "")
<< "#" << NumberOfOwnDescriptors() << ": "
<< Brief(instance_descriptors());
......@@ -1443,7 +1444,6 @@ void PrototypeInfo::PrototypeInfoPrint(std::ostream& os) { // NOLINT
os << "\n - weak cell: " << Brief(weak_cell());
os << "\n - prototype users: " << Brief(prototype_users());
os << "\n - registry slot: " << registry_slot();
os << "\n - validity cell: " << Brief(validity_cell());
os << "\n - object create map: " << Brief(object_create_map());
os << "\n - should_be_fast_map: " << should_be_fast_map();
os << "\n";
......
......@@ -12432,28 +12432,26 @@ namespace {
// This function must be kept in sync with
// AccessorAssembler::InvalidateValidityCellIfPrototype() which does pre-checks
// before jumping here.
PrototypeInfo* InvalidateOnePrototypeValidityCellInternal(Map* map) {
void InvalidateOnePrototypeValidityCellInternal(Map* map) {
DCHECK(map->is_prototype_map());
if (FLAG_trace_prototype_users) {
PrintF("Invalidating prototype map %p 's cell\n",
reinterpret_cast<void*>(map));
}
Object* maybe_proto_info = map->prototype_info();
if (!maybe_proto_info->IsPrototypeInfo()) return nullptr;
PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
Object* maybe_cell = proto_info->validity_cell();
Object* maybe_cell = map->prototype_validity_cell();
if (maybe_cell->IsCell()) {
// Just set the value; the cell will be replaced lazily.
Cell* cell = Cell::cast(maybe_cell);
cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid));
}
return proto_info;
}
void InvalidatePrototypeChainsInternal(Map* map) {
PrototypeInfo* proto_info = InvalidateOnePrototypeValidityCellInternal(map);
if (proto_info == nullptr) return;
InvalidateOnePrototypeValidityCellInternal(map);
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());
// For now, only maps register themselves as users.
Map* user;
......@@ -12544,9 +12542,8 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
// will be invalidated when necessary.
JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
isolate);
Handle<PrototypeInfo> proto_info =
GetOrCreatePrototypeInfo(prototype, isolate);
Object* maybe_cell = proto_info->validity_cell();
Object* maybe_cell = prototype->map()->prototype_validity_cell();
// Return existing cell if it's still valid.
if (maybe_cell->IsCell()) {
Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
......@@ -12557,21 +12554,17 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
// Otherwise create a new cell.
Handle<Cell> cell = isolate->factory()->NewCell(
handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
proto_info->set_validity_cell(*cell);
prototype->map()->set_prototype_validity_cell(*cell);
return cell;
}
// static
bool Map::IsPrototypeChainInvalidated(Map* map) {
DCHECK(map->is_prototype_map());
Object* maybe_proto_info = map->prototype_info();
if (maybe_proto_info->IsPrototypeInfo()) {
PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
Object* maybe_cell = proto_info->validity_cell();
if (maybe_cell->IsCell()) {
Cell* cell = Cell::cast(maybe_cell);
return cell->value() == Smi::FromInt(Map::kPrototypeChainInvalid);
}
Object* maybe_cell = map->prototype_validity_cell();
if (maybe_cell->IsCell()) {
Cell* cell = Cell::cast(maybe_cell);
return cell->value() != Smi::FromInt(Map::kPrototypeChainValid);
}
return true;
}
......
......@@ -2934,13 +2934,7 @@ class PrototypeInfo : public Struct {
// is stored. Returns UNREGISTERED if this prototype has not been registered.
inline int registry_slot() const;
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]
inline int bit_field() const;
inline void set_bit_field(int bit_field);
......
......@@ -660,6 +660,7 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
ACCESSORS(Map, weak_cell_cache, Object, kWeakCellCacheOffset)
ACCESSORS(Map, prototype_validity_cell, Object, kPrototypeValidityCellOffset)
ACCESSORS(Map, constructor_or_backpointer, Object,
kConstructorOrBackPointerOffset)
......
......@@ -559,6 +559,20 @@ class Map : public HeapObject {
// [weak cell cache]: cache that stores a weak cell pointing to this map.
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 int LastAdded() const;
......@@ -773,6 +787,7 @@ class Map : public HeapObject {
V(kLayoutDescriptorOffset, FLAG_unbox_double_fields ? kPointerSize : 0) \
V(kDependentCodeOffset, kPointerSize) \
V(kWeakCellCacheOffset, kPointerSize) \
V(kPrototypeValidityCellOffset, kPointerSize) \
V(kPointerFieldsEndOffset, 0) \
/* Total size. */ \
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