[runtime] Stop using Map::unused_property_fields() byte.
The unused properties fields number is calculatable via used in-object properties count and we can drop it now. Bug: chromium:774644 Change-Id: I7388af7772a8e793593fabc46527886cf2e36095 Reviewed-on: https://chromium-review.googlesource.com/781465 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Commit-Queue: Igor Sheludko <ishell@chromium.org> Commit-Queue: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#49542}
This commit is contained in:
parent
572210e731
commit
d8c355fcac
@ -2569,10 +2569,11 @@ void CodeStubAssembler::InitializeJSObjectBodyWithSlackTracking(
|
||||
MachineRepresentation::kWord32);
|
||||
STATIC_ASSERT(Map::kSlackTrackingCounterEnd == 1);
|
||||
|
||||
Node* unused_fields = LoadObjectField(map, Map::kUnusedPropertyFieldsOffset,
|
||||
MachineType::Uint8());
|
||||
Node* used_size = IntPtrSub(
|
||||
instance_size, TimesPointerSize(ChangeUint32ToWord(unused_fields)));
|
||||
// The object still has in-object slack therefore the |unsed_or_unused|
|
||||
// field contain the "used" value.
|
||||
Node* used_size = TimesPointerSize(ChangeUint32ToWord(
|
||||
LoadObjectField(map, Map::kUsedOrUnusedInstanceSizeInWordsOffset,
|
||||
MachineType::Uint8())));
|
||||
|
||||
Comment("iInitialize filler fields");
|
||||
InitializeFieldsWithRoot(object, used_size, instance_size,
|
||||
|
@ -2396,6 +2396,7 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
|
||||
map->set_map_after_allocation(reinterpret_cast<Map*>(root(kMetaMapRootIndex)),
|
||||
SKIP_WRITE_BARRIER);
|
||||
map->set_instance_type(instance_type);
|
||||
WRITE_BYTE_FIELD(map, Map::kSoonToBeInstanceTypeTooOffset, 0);
|
||||
map->set_instance_size(instance_size);
|
||||
// Initialize to only containing tagged fields.
|
||||
if (FLAG_unbox_double_fields) {
|
||||
@ -2431,6 +2432,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
|
||||
map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
|
||||
map->set_constructor_or_backpointer(null_value(), SKIP_WRITE_BARRIER);
|
||||
map->set_instance_size(instance_size);
|
||||
WRITE_BYTE_FIELD(map, Map::kSoonToBeInstanceTypeTooOffset, 0);
|
||||
if (map->IsJSObjectMap()) {
|
||||
map->SetInObjectPropertiesStartInWords(instance_size / kPointerSize -
|
||||
inobject_properties);
|
||||
|
@ -3140,33 +3140,33 @@ void Map::set_instance_type(InstanceType value) {
|
||||
WRITE_BYTE_FIELD(this, kInstanceTypeOffset, value);
|
||||
}
|
||||
|
||||
int Map::unused_property_fields() const {
|
||||
return READ_BYTE_FIELD(this, kUnusedPropertyFieldsOffset);
|
||||
}
|
||||
|
||||
int Map::UnusedPropertyFields() const {
|
||||
VerifyUnusedPropertyFields();
|
||||
return unused_property_fields();
|
||||
int value = used_or_unused_instance_size_in_words();
|
||||
DCHECK_IMPLIES(!IsJSObjectMap(), value == 0);
|
||||
int unused;
|
||||
if (value >= JSObject::kFieldsAdded) {
|
||||
unused = instance_size_in_words() - value;
|
||||
} else {
|
||||
// For out of object properties "used_or_unused_instance_size_in_words"
|
||||
// byte encodes the slack in the property array.
|
||||
unused = value;
|
||||
}
|
||||
return unused;
|
||||
}
|
||||
|
||||
void Map::set_unused_property_fields(int value) {
|
||||
WRITE_BYTE_FIELD(this, kUnusedPropertyFieldsOffset, Min(value, 255));
|
||||
int Map::used_or_unused_instance_size_in_words() const {
|
||||
return READ_BYTE_FIELD(this, kUsedOrUnusedInstanceSizeInWordsOffset);
|
||||
}
|
||||
|
||||
int Map::used_instance_size_in_words() const {
|
||||
return READ_BYTE_FIELD(this, kUsedInstanceSizeInWordsOffset);
|
||||
}
|
||||
|
||||
void Map::set_used_instance_size_in_words(int value) {
|
||||
void Map::set_used_or_unused_instance_size_in_words(int value) {
|
||||
DCHECK_LE(0, value);
|
||||
DCHECK_LE(value, 255);
|
||||
WRITE_BYTE_FIELD(this, kUsedInstanceSizeInWordsOffset,
|
||||
WRITE_BYTE_FIELD(this, kUsedOrUnusedInstanceSizeInWordsOffset,
|
||||
static_cast<byte>(value));
|
||||
VerifyUnusedPropertyFields();
|
||||
}
|
||||
|
||||
int Map::UsedInstanceSize() const {
|
||||
int words = used_instance_size_in_words();
|
||||
int words = used_or_unused_instance_size_in_words();
|
||||
if (words < JSObject::kFieldsAdded) {
|
||||
// All in-object properties are used and the words is tracking the slack
|
||||
// in the property array.
|
||||
@ -3179,55 +3179,53 @@ void Map::SetInObjectUnusedPropertyFields(int value) {
|
||||
STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kPointerSize);
|
||||
if (!IsJSObjectMap()) {
|
||||
DCHECK_EQ(0, value);
|
||||
set_unused_property_fields(0);
|
||||
set_used_instance_size_in_words(0);
|
||||
set_used_or_unused_instance_size_in_words(0);
|
||||
DCHECK_EQ(0, UnusedPropertyFields());
|
||||
return;
|
||||
}
|
||||
DCHECK_LE(0, value);
|
||||
DCHECK_LE(value, GetInObjectProperties());
|
||||
set_unused_property_fields(value);
|
||||
int used_inobject_properties = GetInObjectProperties() - value;
|
||||
set_used_instance_size_in_words(
|
||||
set_used_or_unused_instance_size_in_words(
|
||||
GetInObjectPropertyOffset(used_inobject_properties) / kPointerSize);
|
||||
VerifyUnusedPropertyFields();
|
||||
DCHECK_EQ(value, UnusedPropertyFields());
|
||||
}
|
||||
|
||||
void Map::SetOutOfObjectUnusedPropertyFields(int value) {
|
||||
STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kPointerSize);
|
||||
DCHECK_LE(0, value);
|
||||
DCHECK_LT(value, JSObject::kFieldsAdded);
|
||||
set_unused_property_fields(value);
|
||||
// For out of object properties "used_instance_size_in_words" byte encodes
|
||||
// the slack in the property array.
|
||||
set_used_instance_size_in_words(value);
|
||||
VerifyUnusedPropertyFields();
|
||||
set_used_or_unused_instance_size_in_words(value);
|
||||
DCHECK_EQ(value, UnusedPropertyFields());
|
||||
}
|
||||
|
||||
void Map::CopyUnusedPropertyFields(Map* map) {
|
||||
set_unused_property_fields(map->unused_property_fields());
|
||||
set_used_instance_size_in_words(map->used_instance_size_in_words());
|
||||
VerifyUnusedPropertyFields();
|
||||
set_used_or_unused_instance_size_in_words(
|
||||
map->used_or_unused_instance_size_in_words());
|
||||
DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
|
||||
}
|
||||
|
||||
void Map::AccountAddedPropertyField() {
|
||||
// Update used instance size and unused property fields number.
|
||||
STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kPointerSize);
|
||||
// Update unused_property_fields.
|
||||
int new_unused = unused_property_fields() - 1;
|
||||
#ifdef DEBUG
|
||||
int new_unused = UnusedPropertyFields() - 1;
|
||||
if (new_unused < 0) new_unused += JSObject::kFieldsAdded;
|
||||
set_unused_property_fields(new_unused);
|
||||
// Update used_instance_size_in_words.
|
||||
int value = used_instance_size_in_words();
|
||||
#endif
|
||||
int value = used_or_unused_instance_size_in_words();
|
||||
if (value >= JSObject::kFieldsAdded) {
|
||||
if (value == instance_size_in_words()) {
|
||||
AccountAddedOutOfObjectPropertyField(0);
|
||||
} else {
|
||||
// The property is added in-object, so simply increment the counter.
|
||||
set_used_instance_size_in_words(value + 1);
|
||||
set_used_or_unused_instance_size_in_words(value + 1);
|
||||
}
|
||||
} else {
|
||||
AccountAddedOutOfObjectPropertyField(value);
|
||||
}
|
||||
VerifyUnusedPropertyFields();
|
||||
DCHECK_EQ(new_unused, UnusedPropertyFields());
|
||||
}
|
||||
|
||||
void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) {
|
||||
@ -3237,26 +3235,8 @@ void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) {
|
||||
}
|
||||
DCHECK_GE(unused_in_property_array, 0);
|
||||
DCHECK_LT(unused_in_property_array, JSObject::kFieldsAdded);
|
||||
set_used_instance_size_in_words(unused_in_property_array);
|
||||
}
|
||||
|
||||
void Map::VerifyUnusedPropertyFields() const {
|
||||
#ifdef DEBUG
|
||||
if (!IsJSObjectMap()) {
|
||||
DCHECK_EQ(unused_property_fields(), used_instance_size_in_words());
|
||||
} else {
|
||||
int value = used_instance_size_in_words();
|
||||
int unused;
|
||||
if (value >= JSObject::kFieldsAdded) {
|
||||
unused = instance_size_in_words() - value;
|
||||
} else {
|
||||
// For out of object properties "used_instance_size_in_words" byte encodes
|
||||
// the slack in the property array.
|
||||
unused = value;
|
||||
}
|
||||
DCHECK_EQ(unused_property_fields(), unused);
|
||||
}
|
||||
#endif
|
||||
set_used_or_unused_instance_size_in_words(unused_in_property_array);
|
||||
DCHECK_EQ(unused_in_property_array, UnusedPropertyFields());
|
||||
}
|
||||
|
||||
byte Map::bit_field() const { return READ_BYTE_FIELD(this, kBitFieldOffset); }
|
||||
|
@ -12317,15 +12317,16 @@ static void GetMinInobjectSlack(Map* map, void* data) {
|
||||
|
||||
|
||||
static void ShrinkInstanceSize(Map* map, void* data) {
|
||||
#ifdef DEBUG
|
||||
int old_visitor_id = Map::GetVisitorId(map);
|
||||
#endif
|
||||
int slack = *reinterpret_cast<int*>(data);
|
||||
DCHECK_GE(slack, 0);
|
||||
map->set_unused_property_fields(map->unused_property_fields() - slack);
|
||||
#ifdef DEBUG
|
||||
int old_visitor_id = Map::GetVisitorId(map);
|
||||
int new_unused = map->UnusedPropertyFields() - slack;
|
||||
#endif
|
||||
map->set_instance_size(map->instance_size() - slack * kPointerSize);
|
||||
map->set_construction_counter(Map::kNoSlackTracking);
|
||||
DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
|
||||
DCHECK_EQ(new_unused, map->UnusedPropertyFields());
|
||||
}
|
||||
|
||||
static void StopSlackTracking(Map* map, void* data) {
|
||||
|
@ -95,10 +95,11 @@ typedef std::vector<Handle<Map>> MapHandles;
|
||||
// | | If Map for an Object type: |
|
||||
// | | inobject properties start offset in words |
|
||||
// +----------+---------------------------------------------+
|
||||
// | Byte | [used_instance_size_in_words] |
|
||||
// | Byte | [used_or_unused_instance_size_in_words] |
|
||||
// | | For JSObject in fast mode this byte encodes |
|
||||
// | | the size of the object that includes only |
|
||||
// | | the used property fields. |
|
||||
// | | the used property fields or the slack size |
|
||||
// | | in properties backing store. |
|
||||
// +----------+---------------------------------------------+
|
||||
// | Byte | [visitor_id] |
|
||||
// +----+----------+---------------------------------------------+
|
||||
@ -106,8 +107,8 @@ typedef std::vector<Handle<Map>> MapHandles;
|
||||
// `---+----------+---------------------------------------------+
|
||||
// | Byte | [instance_type] |
|
||||
// +----------+---------------------------------------------+
|
||||
// | Byte | [unused_property_fields] number of unused |
|
||||
// | | property fields in JSObject (for fast-mode) |
|
||||
// | Byte | Free byte, soon will be used as a second |
|
||||
// | | byte of [instance_type]. |
|
||||
// +----------+---------------------------------------------+
|
||||
// | Byte | [bit_field] |
|
||||
// | | - has_non_instance_prototype (bit 0) |
|
||||
@ -199,24 +200,13 @@ class Map : public HeapObject {
|
||||
inline InstanceType instance_type() const;
|
||||
inline void set_instance_type(InstanceType value);
|
||||
|
||||
// Tells how many unused property fields are available in the
|
||||
// instance (only used for JSObject in fast mode).
|
||||
inline int unused_property_fields() const;
|
||||
inline void set_unused_property_fields(int value);
|
||||
|
||||
// This byte encodes the instance size without the slack.
|
||||
// Let H be JSObject::kHeaderSize / kPointerSize.
|
||||
// If value >= H then:
|
||||
// - all field properties are stored in the object.
|
||||
// - there is no property array.
|
||||
// - value * kPointerSize is the actual object size without the slack.
|
||||
// Otherwise:
|
||||
// - there is no slack in the object.
|
||||
// - the property array has value slack slots.
|
||||
// Note that this encoding requires that H = JSObject::kFieldsAdded.
|
||||
DECL_INT_ACCESSORS(used_instance_size_in_words)
|
||||
// Returns the size of the used in-object area including object header
|
||||
// (only used for JSObject in fast mode, for the other kinds of objects it
|
||||
// is equal to the instance size).
|
||||
inline int UsedInstanceSize() const;
|
||||
|
||||
// Tells how many unused property fields (in-object or out-of object) are
|
||||
// available in the instance (only used for JSObject in fast mode).
|
||||
inline int UnusedPropertyFields() const;
|
||||
// Updates the counters tracking unused fields in the object.
|
||||
inline void SetInObjectUnusedPropertyFields(int unused_property_fields);
|
||||
@ -226,7 +216,6 @@ class Map : public HeapObject {
|
||||
inline void AccountAddedPropertyField();
|
||||
inline void AccountAddedOutOfObjectPropertyField(
|
||||
int unused_in_property_array);
|
||||
inline void VerifyUnusedPropertyFields() const;
|
||||
|
||||
// Bit field.
|
||||
inline byte bit_field() const;
|
||||
@ -738,12 +727,11 @@ class Map : public HeapObject {
|
||||
/* Raw data fields. */ \
|
||||
V(kInstanceSizeInWordsOffset, kUInt8Size) \
|
||||
V(kInObjectPropertiesStartOrConstructorFunctionIndexOffset, kUInt8Size) \
|
||||
V(kUsedInstanceSizeInWordsOffset, kUInt8Size) \
|
||||
V(kUsedOrUnusedInstanceSizeInWordsOffset, kUInt8Size) \
|
||||
V(kVisitorIdOffset, kUInt8Size) \
|
||||
V(kInstanceTypeOffset, kUInt8Size) \
|
||||
/* TODO(ulan): Free this byte after unused_property_fields are */ \
|
||||
/* computed using the used_instance_size_in_words() byte. */ \
|
||||
V(kUnusedPropertyFieldsOffset, kUInt8Size) \
|
||||
/* TODO(ishell): Extend kInstanceTypeOffset field to two bytes. */ \
|
||||
V(kSoonToBeInstanceTypeTooOffset, kUInt8Size) \
|
||||
V(kBitFieldOffset, kUInt8Size) \
|
||||
V(kBitField2Offset, kUInt8Size) \
|
||||
V(kBitField3Offset, kUInt32Size) \
|
||||
@ -810,6 +798,19 @@ class Map : public HeapObject {
|
||||
static VisitorId GetVisitorId(Map* map);
|
||||
|
||||
private:
|
||||
// This byte encodes either the instance size without the in-object slack or
|
||||
// the slack size in properties backing store.
|
||||
// Let H be JSObject::kHeaderSize / kPointerSize.
|
||||
// If value >= H then:
|
||||
// - all field properties are stored in the object.
|
||||
// - there is no property array.
|
||||
// - value * kPointerSize is the actual object size without the slack.
|
||||
// Otherwise:
|
||||
// - there is no slack in the object.
|
||||
// - the property array has value slack slots.
|
||||
// Note that this encoding requires that H = JSObject::kFieldsAdded.
|
||||
DECL_INT_ACCESSORS(used_or_unused_instance_size_in_words)
|
||||
|
||||
// Returns the map that this (root) map transitions to if its elements_kind
|
||||
// is changed to |elements_kind|, or |nullptr| if no such map is cached yet.
|
||||
Map* LookupElementsTransitionMap(ElementsKind elements_kind);
|
||||
|
@ -102,7 +102,7 @@ bool IsObjectShrinkable(JSObject* obj) {
|
||||
CcTest::i_isolate()->factory()->one_pointer_filler_map();
|
||||
|
||||
int inobject_properties = obj->map()->GetInObjectProperties();
|
||||
int unused = obj->map()->unused_property_fields();
|
||||
int unused = obj->map()->UnusedPropertyFields();
|
||||
if (unused == 0) return false;
|
||||
|
||||
for (int i = inobject_properties - unused; i < inobject_properties; i++) {
|
||||
@ -227,13 +227,13 @@ TEST(JSObjectComplex) {
|
||||
CHECK(!IsObjectShrinkable(*obj5));
|
||||
|
||||
CHECK_EQ(5, obj1->map()->GetInObjectProperties());
|
||||
CHECK_EQ(4, obj1->map()->unused_property_fields());
|
||||
CHECK_EQ(4, obj1->map()->UnusedPropertyFields());
|
||||
|
||||
CHECK_EQ(5, obj3->map()->GetInObjectProperties());
|
||||
CHECK_EQ(2, obj3->map()->unused_property_fields());
|
||||
CHECK_EQ(2, obj3->map()->UnusedPropertyFields());
|
||||
|
||||
CHECK_EQ(5, obj5->map()->GetInObjectProperties());
|
||||
CHECK_EQ(0, obj5->map()->unused_property_fields());
|
||||
CHECK_EQ(0, obj5->map()->UnusedPropertyFields());
|
||||
|
||||
// Since slack tracking is complete, the new objects should not be shrinkable.
|
||||
obj1 = CompileRunI<JSObject>("new A(1);");
|
||||
|
Loading…
Reference in New Issue
Block a user