Commit b276e30c authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[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: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59402}
parent cb935071
......@@ -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(&current_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");
serializer_->PutRepeat(repeat_count);
} else {
sink_->Put(kFixedRepeatStart + repeat_count, "FixedRepeat");
bytes_processed_so_far_ += kTaggedSize;
++current;
}
} else {
// Now write the object itself.
if (reference_type == HeapObjectReferenceType::WEAK) {
sink_->Put(kWeakPrefix, "WeakReference");
}
serializer_->SerializeObject(current_contents, kPlain, kStartOfObject,
0);
bytes_processed_so_far_ += kTaggedSize;
++current;
}
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,
......
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