[snapshot][ptr-compr][cleanup] Write repeats as a prefix
... rather than as a suffix. This avoids reading previous values which in turn will make things simpler from the pointer compression point of view in a sense that this is a step towards replacing UnalignedSlot with MaybeObjectSlot. Bug: v8:8794, v8:8562 Change-Id: I9a9b4a01f73b8058074d337b7e9e9f75fa1c9de0 Reviewed-on: https://chromium-review.googlesource.com/c/1456037 Commit-Queue: Igor Sheludko <ishell@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#59402}
This commit is contained in:
parent
cb935071b1
commit
b276e30c48
@ -50,12 +50,6 @@ class UnalignedSlot {
|
||||
memcpy(&result, reinterpret_cast<void*>(ptr_), sizeof(result));
|
||||
return MaybeObject(result);
|
||||
}
|
||||
MaybeObject ReadPrevious() {
|
||||
Address result;
|
||||
memcpy(&result, reinterpret_cast<void*>(ptr_ - kPointerSize),
|
||||
sizeof(result));
|
||||
return MaybeObject(result);
|
||||
}
|
||||
inline void Write(Address value) {
|
||||
memcpy(reinterpret_cast<void*>(ptr_), &value, sizeof(value));
|
||||
}
|
||||
@ -115,8 +109,8 @@ Deserializer::~Deserializer() {
|
||||
// process. It is also called on the body of each function.
|
||||
void Deserializer::VisitRootPointers(Root root, const char* description,
|
||||
FullObjectSlot start, FullObjectSlot end) {
|
||||
// The space must be new space. Any other space would cause ReadChunk to try
|
||||
// to update the remembered using nullptr as the address.
|
||||
// We are reading to a location outside of JS heap, so pass NEW_SPACE to
|
||||
// avoid triggering write barriers.
|
||||
// TODO(ishell): this will not work once we actually compress pointers.
|
||||
STATIC_ASSERT(kTaggedSize == kSystemPointerSize);
|
||||
ReadData(UnalignedSlot(start.address()), UnalignedSlot(end.address()),
|
||||
@ -413,6 +407,26 @@ void Deserializer::ReadObject(int space_number, UnalignedSlot write_back,
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
UnalignedSlot Deserializer::ReadRepeatedObject(UnalignedSlot current,
|
||||
int repeat_count) {
|
||||
CHECK_LE(2, repeat_count);
|
||||
MaybeObject object;
|
||||
// We are reading to a location outside of JS heap, so pass NEW_SPACE to
|
||||
// avoid triggering write barriers.
|
||||
bool filled = ReadData(UnalignedSlot(&object), UnalignedSlot(&object + 1),
|
||||
NEW_SPACE, kNullAddress);
|
||||
CHECK(filled);
|
||||
DCHECK(HAS_HEAP_OBJECT_TAG(object.ptr()));
|
||||
DCHECK(!Heap::InYoungGeneration(object));
|
||||
for (int i = 0; i < repeat_count; i++) {
|
||||
// Repeated values are not subject to the write barrier so we don't need
|
||||
// to trigger it.
|
||||
UnalignedCopy(current, object);
|
||||
current.Advance();
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
static void NoExternalReferencesCallback() {
|
||||
// The following check will trigger if a function or object template
|
||||
// with references to native functions have been deserialized from
|
||||
@ -646,13 +660,8 @@ bool Deserializer::ReadData(UnalignedSlot current, UnalignedSlot limit,
|
||||
}
|
||||
|
||||
case kVariableRepeat: {
|
||||
int repeats = source_.GetInt();
|
||||
MaybeObject object = current.ReadPrevious();
|
||||
DCHECK(!Heap::InYoungGeneration(object));
|
||||
for (int i = 0; i < repeats; i++) {
|
||||
UnalignedCopy(current, object);
|
||||
current.Advance();
|
||||
}
|
||||
int repeats = DecodeVariableRepeatCount(source_.GetInt());
|
||||
current = ReadRepeatedObject(current, repeats);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -769,13 +778,8 @@ bool Deserializer::ReadData(UnalignedSlot current, UnalignedSlot limit,
|
||||
|
||||
STATIC_ASSERT(kNumberOfFixedRepeat == 16);
|
||||
SIXTEEN_CASES(kFixedRepeat) {
|
||||
int repeats = data - kFixedRepeatStart;
|
||||
MaybeObject object = current.ReadPrevious();
|
||||
DCHECK(!Heap::InYoungGeneration(object));
|
||||
for (int i = 0; i < repeats; i++) {
|
||||
UnalignedCopy(current, object);
|
||||
current.Advance();
|
||||
}
|
||||
int repeats = DecodeFixedRepeatCount(data);
|
||||
current = ReadRepeatedObject(current, repeats);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -139,6 +139,8 @@ class Deserializer : public SerializerDeserializer {
|
||||
void ReadObject(int space_number, UnalignedSlot write_back,
|
||||
HeapObjectReferenceType reference_type);
|
||||
|
||||
UnalignedSlot ReadRepeatedObject(UnalignedSlot current, int repeat_count);
|
||||
|
||||
// Special handling for serialized code like hooking up internalized strings.
|
||||
HeapObject PostProcessNewObject(HeapObject obj, int space);
|
||||
|
||||
|
@ -262,7 +262,6 @@ class SerializerDeserializer : public RootVisitor {
|
||||
static const int kNumberOfFixedRepeat = 0x10;
|
||||
// 0xe0..0xef
|
||||
static const int kFixedRepeat = 0xe0;
|
||||
static const int kFixedRepeatStart = kFixedRepeat - 1;
|
||||
|
||||
// 8 hot (recently seen or back-referenced) objects with optional skip.
|
||||
static const int kNumberOfHotObjects = 8;
|
||||
@ -279,6 +278,39 @@ class SerializerDeserializer : public RootVisitor {
|
||||
// Sentinel after a new object to indicate that double alignment is needed.
|
||||
static const int kDoubleAlignmentSentinel = 0;
|
||||
|
||||
// Repeat count encoding helpers.
|
||||
static const int kFirstEncodableRepeatCount = 2;
|
||||
static const int kLastEncodableFixedRepeatCount =
|
||||
kFirstEncodableRepeatCount + kNumberOfFixedRepeat - 1;
|
||||
static const int kFirstEncodableVariableRepeatCount =
|
||||
kLastEncodableFixedRepeatCount + 1;
|
||||
|
||||
// Encodes repeat count into a fixed repeat bytecode.
|
||||
static int EncodeFixedRepeat(int repeat_count) {
|
||||
DCHECK(IsInRange(repeat_count, kFirstEncodableRepeatCount,
|
||||
kLastEncodableFixedRepeatCount));
|
||||
return kFixedRepeat + repeat_count - kFirstEncodableRepeatCount;
|
||||
}
|
||||
|
||||
// Decodes repeat count from a fixed repeat bytecode.
|
||||
static int DecodeFixedRepeatCount(int bytecode) {
|
||||
DCHECK(
|
||||
IsInRange(bytecode, kFixedRepeat, kFixedRepeat + kNumberOfFixedRepeat));
|
||||
return bytecode - kFixedRepeat + kFirstEncodableRepeatCount;
|
||||
}
|
||||
|
||||
// Encodes repeat count into a serialized variable repeat count value.
|
||||
static int EncodeVariableRepeatCount(int repeat_count) {
|
||||
DCHECK_LE(kFirstEncodableVariableRepeatCount, repeat_count);
|
||||
return repeat_count - kFirstEncodableVariableRepeatCount;
|
||||
}
|
||||
|
||||
// Decodes repeat count from a serialized variable repeat count value.
|
||||
static int DecodeVariableRepeatCount(int value) {
|
||||
DCHECK_LE(0, value);
|
||||
return value + kFirstEncodableVariableRepeatCount;
|
||||
}
|
||||
|
||||
// ---------- member variable ----------
|
||||
HotObjectsList hot_objects_;
|
||||
};
|
||||
|
@ -289,6 +289,15 @@ void Serializer::PutNextChunk(int space) {
|
||||
sink_.Put(space, "NextChunkSpace");
|
||||
}
|
||||
|
||||
void Serializer::PutRepeat(int repeat_count) {
|
||||
if (repeat_count <= kLastEncodableFixedRepeatCount) {
|
||||
sink_.Put(EncodeFixedRepeat(repeat_count), "FixedRepeat");
|
||||
} else {
|
||||
sink_.Put(kVariableRepeat, "VariableRepeat");
|
||||
sink_.PutInt(EncodeVariableRepeatCount(repeat_count), "repeat count");
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::Pad(int padding_offset) {
|
||||
// The non-branching GetInt will read up to 3 bytes too far, so we need
|
||||
// to pad the snapshot to make sure we don't read over the end.
|
||||
@ -693,37 +702,33 @@ void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
|
||||
while (current < end &&
|
||||
(*current)->GetHeapObject(¤t_contents, &reference_type)) {
|
||||
RootIndex root_index;
|
||||
// Compute repeat count and write repeat prefix if applicable.
|
||||
// Repeats are not subject to the write barrier so we can only use
|
||||
// immortal immovable root members. They are never in new space.
|
||||
if (current != start &&
|
||||
MaybeObjectSlot repeat_end = current + 1;
|
||||
if (repeat_end < end &&
|
||||
serializer_->root_index_map()->Lookup(current_contents,
|
||||
&root_index) &&
|
||||
RootsTable::IsImmortalImmovable(root_index) &&
|
||||
*current == *(current - 1)) {
|
||||
*current == *repeat_end) {
|
||||
DCHECK_EQ(reference_type, HeapObjectReferenceType::STRONG);
|
||||
DCHECK(!Heap::InYoungGeneration(current_contents));
|
||||
int repeat_count = 1;
|
||||
while (current + repeat_count < end - 1 &&
|
||||
*(current + repeat_count) == *current) {
|
||||
repeat_count++;
|
||||
while (repeat_end < end && *repeat_end == *current) {
|
||||
repeat_end++;
|
||||
}
|
||||
current += repeat_count;
|
||||
int repeat_count = static_cast<int>(repeat_end - current);
|
||||
current = repeat_end;
|
||||
bytes_processed_so_far_ += repeat_count * kTaggedSize;
|
||||
if (repeat_count > kNumberOfFixedRepeat) {
|
||||
sink_->Put(kVariableRepeat, "VariableRepeat");
|
||||
sink_->PutInt(repeat_count, "repeat count");
|
||||
} else {
|
||||
sink_->Put(kFixedRepeatStart + repeat_count, "FixedRepeat");
|
||||
}
|
||||
serializer_->PutRepeat(repeat_count);
|
||||
} else {
|
||||
if (reference_type == HeapObjectReferenceType::WEAK) {
|
||||
sink_->Put(kWeakPrefix, "WeakReference");
|
||||
}
|
||||
serializer_->SerializeObject(current_contents, kPlain, kStartOfObject,
|
||||
0);
|
||||
bytes_processed_so_far_ += kTaggedSize;
|
||||
++current;
|
||||
}
|
||||
// Now write the object itself.
|
||||
if (reference_type == HeapObjectReferenceType::WEAK) {
|
||||
sink_->Put(kWeakPrefix, "WeakReference");
|
||||
}
|
||||
serializer_->SerializeObject(current_contents, kPlain, kStartOfObject, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +209,7 @@ class Serializer : public SerializerDeserializer {
|
||||
// Emit alignment prefix if necessary, return required padding space in bytes.
|
||||
int PutAlignmentPrefix(HeapObject object);
|
||||
void PutNextChunk(int space);
|
||||
void PutRepeat(int repeat_count);
|
||||
|
||||
// Returns true if the object was successfully serialized as a root.
|
||||
bool SerializeRoot(HeapObject obj, HowToCode how_to_code,
|
||||
|
Loading…
Reference in New Issue
Block a user