Commit 039617d7 authored by ulan's avatar ulan Committed by Commit bot

Handle ExternalStrings directly in the serializer without ObjectVisitor.

The serializer already has code that special cases for some external
strings. We can handle all external strings in one place instead of
splitting the logic between the serializer and the object visitor.

The main benefit is that we remove two virtual functions from the
ObjectVisitor and thus simplify it for all other users.

BUG=chromium:709075

Review-Url: https://codereview.chromium.org/2799943002
Cr-Commit-Position: refs/heads/master@{#44485}
parent e6ca0146
...@@ -1679,10 +1679,6 @@ class RecordMigratedSlotVisitor final : public ObjectVisitor { ...@@ -1679,10 +1679,6 @@ class RecordMigratedSlotVisitor final : public ObjectVisitor {
inline void VisitExternalReference(RelocInfo* rinfo) final {} inline void VisitExternalReference(RelocInfo* rinfo) final {}
inline void VisitExternalReference(Address* p) final {} inline void VisitExternalReference(Address* p) final {}
inline void VisitRuntimeEntry(RelocInfo* rinfo) final {} inline void VisitRuntimeEntry(RelocInfo* rinfo) final {}
inline void VisitExternalOneByteString(
v8::String::ExternalOneByteStringResource** resource) final {}
inline void VisitExternalTwoByteString(
v8::String::ExternalStringResource** resource) final {}
inline void VisitInternalReference(RelocInfo* rinfo) final {} inline void VisitInternalReference(RelocInfo* rinfo) final {}
private: private:
......
...@@ -329,16 +329,10 @@ class ExternalOneByteString::BodyDescriptor final : public BodyDescriptorBase { ...@@ -329,16 +329,10 @@ class ExternalOneByteString::BodyDescriptor final : public BodyDescriptorBase {
template <typename ObjectVisitor> template <typename ObjectVisitor>
static inline void IterateBody(HeapObject* obj, int object_size, static inline void IterateBody(HeapObject* obj, int object_size,
ObjectVisitor* v) { ObjectVisitor* v) {
typedef v8::String::ExternalOneByteStringResource Resource;
v->VisitExternalOneByteString(reinterpret_cast<Resource**>(
HeapObject::RawField(obj, kResourceOffset)));
} }
template <typename StaticVisitor> template <typename StaticVisitor>
static inline void IterateBody(HeapObject* obj, int object_size) { static inline void IterateBody(HeapObject* obj, int object_size) {
typedef v8::String::ExternalOneByteStringResource Resource;
StaticVisitor::VisitExternalOneByteString(reinterpret_cast<Resource**>(
HeapObject::RawField(obj, kResourceOffset)));
} }
static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } static inline int SizeOf(Map* map, HeapObject* object) { return kSize; }
...@@ -351,16 +345,10 @@ class ExternalTwoByteString::BodyDescriptor final : public BodyDescriptorBase { ...@@ -351,16 +345,10 @@ class ExternalTwoByteString::BodyDescriptor final : public BodyDescriptorBase {
template <typename ObjectVisitor> template <typename ObjectVisitor>
static inline void IterateBody(HeapObject* obj, int object_size, static inline void IterateBody(HeapObject* obj, int object_size,
ObjectVisitor* v) { ObjectVisitor* v) {
typedef v8::String::ExternalStringResource Resource;
v->VisitExternalTwoByteString(reinterpret_cast<Resource**>(
HeapObject::RawField(obj, kResourceOffset)));
} }
template <typename StaticVisitor> template <typename StaticVisitor>
static inline void IterateBody(HeapObject* obj, int object_size) { static inline void IterateBody(HeapObject* obj, int object_size) {
typedef v8::String::ExternalStringResource Resource;
StaticVisitor::VisitExternalTwoByteString(reinterpret_cast<Resource**>(
HeapObject::RawField(obj, kResourceOffset)));
} }
static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } static inline int SizeOf(Map* map, HeapObject* object) { return kSize; }
......
...@@ -10201,12 +10201,6 @@ class ObjectVisitor BASE_EMBEDDED { ...@@ -10201,12 +10201,6 @@ class ObjectVisitor BASE_EMBEDDED {
// Visits a runtime entry in the instruction stream. // Visits a runtime entry in the instruction stream.
virtual void VisitRuntimeEntry(RelocInfo* rinfo) {} virtual void VisitRuntimeEntry(RelocInfo* rinfo) {}
// Visits the resource of an one-byte or two-byte string.
virtual void VisitExternalOneByteString(
v8::String::ExternalOneByteStringResource** resource) {}
virtual void VisitExternalTwoByteString(
v8::String::ExternalStringResource** resource) {}
// Visits a debug call target in the instruction stream. // Visits a debug call target in the instruction stream.
virtual void VisitDebugTarget(RelocInfo* rinfo); virtual void VisitDebugTarget(RelocInfo* rinfo);
......
...@@ -401,6 +401,69 @@ void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space, ...@@ -401,6 +401,69 @@ void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space,
} }
void Serializer::ObjectSerializer::SerializeExternalString() { void Serializer::ObjectSerializer::SerializeExternalString() {
Heap* heap = serializer_->isolate()->heap();
if (object_->map() != heap->native_source_string_map()) {
// Usually we cannot recreate resources for external strings. To work
// around this, external strings are serialized to look like ordinary
// sequential strings.
// The exception are native source code strings, since we can recreate
// their resources.
SerializeExternalStringAsSequentialString();
} else {
DCHECK(object_->IsExternalOneByteString());
DCHECK(ExternalOneByteString::cast(object_)->is_short());
int size = object_->Size();
Map* map = object_->map();
AllocationSpace space =
MemoryChunk::FromAddress(object_->address())->owner()->identity();
SerializePrologue(space, size, map);
// Serialize the rest of the object.
CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize;
typedef v8::String::ExternalOneByteStringResource Resource;
Resource** resource_pointer = reinterpret_cast<Resource**>(
HeapObject::RawField(object_, ExternalString::kResourceOffset));
Address references_start = reinterpret_cast<Address>(resource_pointer);
OutputRawData(references_start);
if (!SerializeExternalNativeSourceString(
Natives::GetBuiltinsCount(), resource_pointer,
Natives::GetSourceCache(heap), kNativesStringResource)) {
bool result = SerializeExternalNativeSourceString(
ExtraNatives::GetBuiltinsCount(), resource_pointer,
ExtraNatives::GetSourceCache(heap), kExtraNativesStringResource);
// One of the strings in the natives cache should match the resource. We
// don't expect any other kinds of external strings here.
USE(result);
DCHECK(result);
}
OutputRawData(object_->address() + size);
}
}
bool Serializer::ObjectSerializer::SerializeExternalNativeSourceString(
int builtin_count,
v8::String::ExternalOneByteStringResource** resource_pointer,
FixedArray* source_cache, int resource_index) {
Isolate* isolate = serializer_->isolate();
for (int i = 0; i < builtin_count; i++) {
Object* source = source_cache->get(i);
if (!source->IsUndefined(isolate)) {
ExternalOneByteString* string = ExternalOneByteString::cast(source);
typedef v8::String::ExternalOneByteStringResource Resource;
const Resource* resource = string->resource();
if (resource == *resource_pointer) {
sink_->Put(resource_index, "NativesStringResource");
sink_->PutSection(i, "NativesStringResourceEnd");
bytes_processed_so_far_ += sizeof(resource);
return true;
}
}
}
return false;
}
void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() {
// Instead of serializing this as an external string, we serialize // Instead of serializing this as an external string, we serialize
// an imaginary sequential string with the same content. // an imaginary sequential string with the same content.
Isolate* isolate = serializer_->isolate(); Isolate* isolate = serializer_->isolate();
...@@ -501,55 +564,45 @@ void Serializer::ObjectSerializer::Serialize() { ...@@ -501,55 +564,45 @@ void Serializer::ObjectSerializer::Serialize() {
PrintF("\n"); PrintF("\n");
} }
// We cannot serialize typed array objects correctly. if (object_->IsExternalString()) {
DCHECK(!object_->IsJSTypedArray()); SerializeExternalString();
} else {
// We cannot serialize typed array objects correctly.
DCHECK(!object_->IsJSTypedArray());
// We don't expect fillers. // We don't expect fillers.
DCHECK(!object_->IsFiller()); DCHECK(!object_->IsFiller());
if (object_->IsScript()) { if (object_->IsScript()) {
// Clear cached line ends. // Clear cached line ends.
Object* undefined = serializer_->isolate()->heap()->undefined_value(); Object* undefined = serializer_->isolate()->heap()->undefined_value();
Script::cast(object_)->set_line_ends(undefined); Script::cast(object_)->set_line_ends(undefined);
} }
if (object_->IsExternalString()) { int size = object_->Size();
Heap* heap = serializer_->isolate()->heap(); Map* map = object_->map();
if (object_->map() != heap->native_source_string_map()) { AllocationSpace space =
// Usually we cannot recreate resources for external strings. To work MemoryChunk::FromAddress(object_->address())->owner()->identity();
// around this, external strings are serialized to look like ordinary SerializePrologue(space, size, map);
// sequential strings.
// The exception are native source code strings, since we can recreate // Serialize the rest of the object.
// their resources. In that case we fall through and leave it to CHECK_EQ(0, bytes_processed_so_far_);
// VisitExternalOneByteString further down. bytes_processed_so_far_ = kPointerSize;
SerializeExternalString();
RecursionScope recursion(serializer_);
// Objects that are immediately post processed during deserialization
// cannot be deferred, since post processing requires the object content.
if (recursion.ExceedsMaximum() && CanBeDeferred(object_)) {
serializer_->QueueDeferredObject(object_);
sink_->Put(kDeferred, "Deferring object content");
return; return;
} }
}
int size = object_->Size();
Map* map = object_->map();
AllocationSpace space =
MemoryChunk::FromAddress(object_->address())->owner()->identity();
SerializePrologue(space, size, map);
// Serialize the rest of the object. UnlinkWeakNextScope unlink_weak_next(object_);
CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize;
RecursionScope recursion(serializer_); object_->IterateBody(map->instance_type(), size, this);
// Objects that are immediately post processed during deserialization OutputRawData(object_->address() + size);
// cannot be deferred, since post processing requires the object content.
if (recursion.ExceedsMaximum() && CanBeDeferred(object_)) {
serializer_->QueueDeferredObject(object_);
sink_->Put(kDeferred, "Deferring object content");
return;
} }
UnlinkWeakNextScope unlink_weak_next(object_);
object_->IterateBody(map->instance_type(), size, this);
OutputRawData(object_->address() + size);
} }
void Serializer::ObjectSerializer::SerializeDeferred() { void Serializer::ObjectSerializer::SerializeDeferred() {
...@@ -715,52 +768,6 @@ void Serializer::ObjectSerializer::VisitCell(RelocInfo* rinfo) { ...@@ -715,52 +768,6 @@ void Serializer::ObjectSerializer::VisitCell(RelocInfo* rinfo) {
bytes_processed_so_far_ += kPointerSize; bytes_processed_so_far_ += kPointerSize;
} }
bool Serializer::ObjectSerializer::SerializeExternalNativeSourceString(
int builtin_count,
v8::String::ExternalOneByteStringResource** resource_pointer,
FixedArray* source_cache, int resource_index) {
Isolate* isolate = serializer_->isolate();
for (int i = 0; i < builtin_count; i++) {
Object* source = source_cache->get(i);
if (!source->IsUndefined(isolate)) {
ExternalOneByteString* string = ExternalOneByteString::cast(source);
typedef v8::String::ExternalOneByteStringResource Resource;
const Resource* resource = string->resource();
if (resource == *resource_pointer) {
sink_->Put(resource_index, "NativesStringResource");
sink_->PutSection(i, "NativesStringResourceEnd");
bytes_processed_so_far_ += sizeof(resource);
return true;
}
}
}
return false;
}
void Serializer::ObjectSerializer::VisitExternalOneByteString(
v8::String::ExternalOneByteStringResource** resource_pointer) {
DCHECK_EQ(serializer_->isolate()->heap()->native_source_string_map(),
object_->map());
DCHECK(ExternalOneByteString::cast(object_)->is_short());
Address references_start = reinterpret_cast<Address>(resource_pointer);
OutputRawData(references_start);
if (SerializeExternalNativeSourceString(
Natives::GetBuiltinsCount(), resource_pointer,
Natives::GetSourceCache(serializer_->isolate()->heap()),
kNativesStringResource)) {
return;
}
if (SerializeExternalNativeSourceString(
ExtraNatives::GetBuiltinsCount(), resource_pointer,
ExtraNatives::GetSourceCache(serializer_->isolate()->heap()),
kExtraNativesStringResource)) {
return;
}
// One of the strings in the natives cache should match the resource. We
// don't expect any other kinds of external strings here.
UNREACHABLE();
}
Address Serializer::ObjectSerializer::PrepareCode() { Address Serializer::ObjectSerializer::PrepareCode() {
Code* code = Code::cast(object_); Code* code = Code::cast(object_);
if (FLAG_predictable) { if (FLAG_predictable) {
......
...@@ -290,24 +290,12 @@ class Serializer::ObjectSerializer : public ObjectVisitor { ...@@ -290,24 +290,12 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
void VisitCodeEntry(Address entry_address) override; void VisitCodeEntry(Address entry_address) override;
void VisitCell(RelocInfo* rinfo) override; void VisitCell(RelocInfo* rinfo) override;
void VisitRuntimeEntry(RelocInfo* reloc) override; void VisitRuntimeEntry(RelocInfo* reloc) override;
// Used for seralizing the external strings that hold the natives source.
void VisitExternalOneByteString(
v8::String::ExternalOneByteStringResource** resource) override;
// We can't serialize a heap with external two byte strings.
void VisitExternalTwoByteString(
v8::String::ExternalStringResource** resource) override {
UNREACHABLE();
}
private: private:
bool TryEncodeDeoptimizationEntry(HowToCode how_to_code, Address target, bool TryEncodeDeoptimizationEntry(HowToCode how_to_code, Address target,
int skip); int skip);
void SerializePrologue(AllocationSpace space, int size, Map* map); void SerializePrologue(AllocationSpace space, int size, Map* map);
bool SerializeExternalNativeSourceString(
int builtin_count,
v8::String::ExternalOneByteStringResource** resource_pointer,
FixedArray* source_cache, int resource_index);
enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn }; enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
// This function outputs or skips the raw data between the last pointer and // This function outputs or skips the raw data between the last pointer and
...@@ -315,8 +303,12 @@ class Serializer::ObjectSerializer : public ObjectVisitor { ...@@ -315,8 +303,12 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
// bytes to skip instead of performing a skip instruction, in case the skip // bytes to skip instead of performing a skip instruction, in case the skip
// can be merged into the next instruction. // can be merged into the next instruction.
int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn); int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
// External strings are serialized in a way to resemble sequential strings.
void SerializeExternalString(); void SerializeExternalString();
void SerializeExternalStringAsSequentialString();
bool SerializeExternalNativeSourceString(
int builtin_count,
v8::String::ExternalOneByteStringResource** resource_pointer,
FixedArray* source_cache, int resource_index);
Address PrepareCode(); Address PrepareCode();
......
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