[vm] Treat the dispatch table as a root in the snapshot.

Additional changes:
* Only serialize a dispatch table in precompiled snapshots.
* Add information in v8 snapshot profiles for the dispatch table.
* Fix a typo in a field name.
* Print the number of Instructions objects (or payloads, for
  precompiled bare instructions mode) in the fake cluster for
  the data section.
* Fix v8 snapshots profiles so objects in memory mapped segments
  and only those are prefixed with "(RO) ".
* Add names for Instructions objects in v8 snapshot profiles
  when we can use the assembly namer.
* Add command line flag for old #define'd false flag.

Change-Id: I1e3be59c7a6312efd76afca560ba465cc17cb22b
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-precomp-win-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138089
Commit-Queue: Teagan Strickland <sstrickl@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Teagan Strickland 2020-03-11 10:40:59 +00:00 committed by commit-bot@chromium.org
parent a5bf30c401
commit ba68d04d3f
6 changed files with 378 additions and 205 deletions

View file

@ -27,10 +27,15 @@
#include "vm/timeline.h"
#include "vm/version.h"
#define LOG_SECTION_BOUNDARIES false
namespace dart {
#if !defined(DART_PRECOMPILED_RUNTIME)
DEFINE_FLAG(bool,
print_cluster_information,
false,
"Print information about clusters written to snapshot");
#endif
#if defined(DART_PRECOMPILER)
DEFINE_FLAG(charp,
write_v8_snapshot_profile_to,
@ -101,27 +106,34 @@ void Deserializer::InitializeHeader(RawObject* raw,
#if !defined(DART_PRECOMPILED_RUNTIME)
void SerializationCluster::WriteAndMeasureAlloc(Serializer* serializer) {
if (LOG_SECTION_BOUNDARIES) {
OS::PrintErr("Data + %" Px ": Alloc %s\n", serializer->bytes_written(),
name_);
}
intptr_t start_size = serializer->bytes_written() + serializer->GetDataSize();
intptr_t start_size = serializer->bytes_written();
intptr_t start_data = serializer->GetDataSize();
intptr_t start_objects = serializer->next_ref_index();
WriteAlloc(serializer);
intptr_t stop_size = serializer->bytes_written() + serializer->GetDataSize();
intptr_t stop_size = serializer->bytes_written();
intptr_t stop_data = serializer->GetDataSize();
intptr_t stop_objects = serializer->next_ref_index();
size_ += (stop_size - start_size);
if (FLAG_print_cluster_information) {
const int hex_size = kWordSize * 2;
OS::PrintErr("Snapshot 0x%0*.*" Px " (%" Pd "), ", hex_size, hex_size,
start_size, stop_size - start_size);
OS::PrintErr("Data 0x%0*.*" Px " (%" Pd "): ", hex_size, hex_size,
start_data, stop_data - start_data);
OS::PrintErr("Alloc %s (%" Pd ")\n", name(), stop_objects - start_objects);
}
size_ += (stop_size - start_size) + (stop_data - start_data);
num_objects_ += (stop_objects - start_objects);
}
void SerializationCluster::WriteAndMeasureFill(Serializer* serializer) {
if (LOG_SECTION_BOUNDARIES) {
OS::PrintErr("Data + %" Px ": Fill %s\n", serializer->bytes_written(),
name_);
}
intptr_t start = serializer->bytes_written();
WriteFill(serializer);
intptr_t stop = serializer->bytes_written();
if (FLAG_print_cluster_information) {
const int hex_size = kWordSize * 2;
OS::PrintErr("Snapshot 0x%0*.*" Px " (%" Pd "): Fill %s\n", hex_size,
hex_size, start, stop - start, name());
}
size_ += (stop - start);
}
@ -2008,8 +2020,11 @@ class PcDescriptorsDeserializationCluster : public DeserializationCluster {
// PcDescriptor, CompressedStackMaps, OneByteString, TwoByteString
class RODataSerializationCluster : public SerializationCluster {
public:
RODataSerializationCluster(const char* name, intptr_t cid)
: SerializationCluster(name), cid_(cid) {}
RODataSerializationCluster(Zone* zone, const char* type, intptr_t cid)
: SerializationCluster(ImageWriter::TagObjectTypeAsReadOnly(zone, type)),
cid_(cid),
objects_(),
type_(type) {}
~RODataSerializationCluster() {}
void Trace(Serializer* s, RawObject* object) {
@ -2037,9 +2052,9 @@ class RODataSerializationCluster : public SerializationCluster {
RawObject* object = objects_[i];
s->AssignRef(object);
if (cid_ == kOneByteStringCid || cid_ == kTwoByteStringCid) {
s->TraceStartWritingObject(name(), object, String::RawCast(object));
s->TraceStartWritingObject(type_, object, String::RawCast(object));
} else {
s->TraceStartWritingObject(name(), object, nullptr);
s->TraceStartWritingObject(type_, object, nullptr);
}
uint32_t offset = s->GetDataOffset(object);
s->TraceDataOffset(offset);
@ -2060,6 +2075,7 @@ class RODataSerializationCluster : public SerializationCluster {
private:
const intptr_t cid_;
GrowableArray<RawObject*> objects_;
const char* const type_;
};
#endif // !DART_PRECOMPILED_RUNTIME
@ -4565,6 +4581,23 @@ void Serializer::TraceEndWritingObject() {
}
}
const char* Serializer::ReadOnlyObjectType(intptr_t cid) {
switch (cid) {
case kPcDescriptorsCid:
return "PcDescriptors";
case kCodeSourceMapCid:
return "CodeSourceMap";
case kCompressedStackMapsCid:
return "CompressedStackMaps";
case kOneByteStringCid:
return "OneByteString";
case kTwoByteStringCid:
return "TwoByteString";
default:
return nullptr;
}
}
SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
@ -4586,18 +4619,8 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
}
if (Snapshot::IncludesCode(kind_)) {
switch (cid) {
case kPcDescriptorsCid:
return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
case kCodeSourceMapCid:
return new (Z) RODataSerializationCluster("(RO)CodeSourceMap", cid);
case kCompressedStackMapsCid:
return new (Z)
RODataSerializationCluster("(RO)CompressedStackMaps", cid);
case kOneByteStringCid:
return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
case kTwoByteStringCid:
return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
if (auto const type = ReadOnlyObjectType(cid)) {
return new (Z) RODataSerializationCluster(Z, type, cid);
}
}
@ -4792,13 +4815,6 @@ intptr_t Serializer::GetDataSize() const {
return image_writer_->data_size();
}
intptr_t Serializer::GetTextSize() const {
if (image_writer_ == NULL) {
return 0;
}
return image_writer_->text_size();
}
void Serializer::Push(RawObject* object) {
if (!object->IsHeapObject()) {
RawSmi* smi = Smi::RawCast(object);
@ -5030,19 +5046,36 @@ void Serializer::PrintSnapshotSizes() {
clusters_by_size.Add(cluster);
}
}
if (GetTextSize() != 0) {
intptr_t text_size = 0;
if (image_writer_ != nullptr) {
auto const text_object_count = image_writer_->GetTextObjectCount();
text_size = image_writer_->text_size();
intptr_t trampoline_count, trampoline_size;
image_writer_->GetTrampolineInfo(&trampoline_count, &trampoline_size);
auto const instructions_count = text_object_count - trampoline_count;
auto const instructions_size = text_size - trampoline_size;
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
"(RO)Instructions", 0, GetTextSize()));
ImageWriter::TagObjectTypeAsReadOnly(zone_, "Instructions"),
instructions_count, instructions_size));
if (trampoline_size > 0) {
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
ImageWriter::TagObjectTypeAsReadOnly(zone_, "Trampoline"),
trampoline_count, trampoline_size));
}
}
// An null dispatch table will serialize to a single byte.
if (dispatch_table_size_ > 1) {
// The dispatch_table_size_ will be 0 if the snapshot did not include a
// dispatch table (i.e., the VM snapshot). For a precompiled isolate
// snapshot, we always serialize at least _one_ byte for the DispatchTable.
if (dispatch_table_size_ > 0) {
auto const dispatch_table = isolate()->dispatch_table();
auto const entry_count =
dispatch_table != nullptr ? dispatch_table->length() : 0;
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
"(RO)DispatchTable", isolate()->dispatch_table()->length(),
dispatch_table_size_));
"DispatchTable", entry_count, dispatch_table_size_));
}
clusters_by_size.Sort(CompareClusters);
double total_size =
static_cast<double>(bytes_written() + GetDataSize() + GetTextSize());
static_cast<double>(bytes_written() + GetDataSize() + text_size);
double cumulative_fraction = 0.0;
for (intptr_t i = 0; i < clusters_by_size.length(); i++) {
SerializationCluster* cluster = clusters_by_size[i];
@ -5178,6 +5211,36 @@ static const char* kObjectStoreFieldNames[] = {
void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
ObjectStore* object_store) {
#if defined(DART_PRECOMPILER)
// We should treat the dispatch table as a root object and trace the
// Code objects it references via entry points. Otherwise, an non-empty
// entry could be invalid on deserialization if the corresponding Code
// object was not reachable from the existing snapshot roots.
//
// Since the dispatch table only stores entry points, we have to find the
// Code objects before entering the NoSafepointScope, since looking up a
// Code object from the entry point cannot be done during one.
auto const dispatch_table = isolate()->dispatch_table();
// Check that we only have dispatch tables in precompiled mode, so we can
// elide them from the snapshot when not creating a precompiled snapshot.
ASSERT(dispatch_table == nullptr || kind() == Snapshot::kFullAOT);
// We collect the Code objects for each entry, storing null if there is none.
auto const dispatch_table_length =
dispatch_table != nullptr ? dispatch_table->length() : 0;
GrowableHandlePtrArray<const Code> dispatch_table_roots(
zone_, dispatch_table_length);
if (dispatch_table != nullptr) {
auto& code = Code::Handle(zone_);
auto const entries = dispatch_table->array();
for (intptr_t i = 0; i < dispatch_table_length; i++) {
auto const entry = entries[i];
code = entry != 0 ? Code::LookupCode(entry) : Code::null();
ASSERT(entry == 0 || !code.IsNull());
dispatch_table_roots.Add(code);
}
}
#endif
NoSafepointScope no_safepoint;
if (num_base_objects == 0) {
@ -5199,6 +5262,15 @@ void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
Push(*p);
}
#if defined(DART_PRECOMPILER)
// Push the Code objects collected from the dispatch table.
for (intptr_t i = 0; i < dispatch_table_length; i++) {
const auto& code = dispatch_table_roots.At(i);
if (code.IsNull()) continue;
Push(code.raw());
}
#endif
Serialize();
// Write roots.
@ -5206,12 +5278,37 @@ void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
WriteRootRef(*p, kObjectStoreFieldNames[p - from]);
}
// Serialize dispatch table.
GrowableArray<RawCode*>* code_objects =
static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
->discovered_objects();
dispatch_table_size_ = DispatchTable::Serialize(
this, isolate()->dispatch_table(), *code_objects);
#if defined(DART_PRECOMPILER)
// Serialize dispatch table for precompiled snapshots only.
if (kind() == Snapshot::kFullAOT) {
GrowableArray<RawCode*>* code_objects =
static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
->discovered_objects();
dispatch_table_size_ = DispatchTable::Serialize(
this, isolate()->dispatch_table(), *code_objects);
ASSERT(dispatch_table_length == 0 || dispatch_table_size_ > 1);
if (profile_writer_ != nullptr) {
// Grab an unused ref index for a unique object id for the dispatch table.
const auto dispatch_table_id = next_ref_index_++;
const V8SnapshotProfileWriter::ObjectId dispatch_table_snapshot_id(
V8SnapshotProfileWriter::kSnapshot, dispatch_table_id);
profile_writer_->AddRoot(dispatch_table_snapshot_id, "dispatch_table");
profile_writer_->SetObjectTypeAndName(dispatch_table_snapshot_id,
"DispatchTable", nullptr);
profile_writer_->AttributeBytesTo(dispatch_table_snapshot_id,
dispatch_table_size_);
for (intptr_t i = 0; i < dispatch_table_length; i++) {
const auto& code = dispatch_table_roots.At(i);
const V8SnapshotProfileWriter::ObjectId code_id(
V8SnapshotProfileWriter::kSnapshot, WriteRefId(code.raw()));
profile_writer_->AttributeReferenceTo(
dispatch_table_snapshot_id,
{code_id, V8SnapshotProfileWriter::Reference::kElement, i});
}
}
}
#endif
#if defined(DEBUG)
Write<int32_t>(kSectionMarker);
@ -5776,11 +5873,13 @@ void Deserializer::ReadIsolateSnapshot(ObjectStore* object_store) {
*p = ReadRef();
}
#if defined(DART_PRECOMPILED_RUNTIME)
// Deserialize dispatch table
const Array& code_array =
Array::Handle(zone_, object_store->code_order_table());
thread()->isolate()->set_dispatch_table(
DispatchTable::Deserialize(this, code_array));
#endif
#if defined(DEBUG)
int32_t section_marker = Read<int32_t>();

View file

@ -246,36 +246,6 @@ class Serializer : public ThreadStackResource {
}
void Align(intptr_t alignment) { stream_.Align(alignment); }
private:
intptr_t WriteRefId(RawObject* object) {
intptr_t id = 0;
if (!object->IsHeapObject()) {
RawSmi* smi = Smi::RawCast(object);
id = smi_ids_.Lookup(smi)->id_;
if (id == 0) {
FATAL("Missing ref");
}
} else {
// The object id weak table holds image offsets for Instructions instead
// of ref indices.
ASSERT(!object->IsInstructions());
id = heap_->GetObjectId(object);
if (id == 0) {
if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
return WriteRefId(Object::null());
}
#if !defined(DART_PRECOMPILED_RUNTIME)
if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
return WriteRefId(Object::null());
}
#endif // !DART_PRECOMPILED_RUNTIME
FATAL("Missing ref");
}
}
return id;
}
public:
void WriteRootRef(RawObject* object, const char* name = nullptr) {
intptr_t id = WriteRefId(object);
WriteUnsigned(id);
@ -382,7 +352,6 @@ class Serializer : public ThreadStackResource {
uint32_t GetDataOffset(RawObject* object) const;
void TraceDataOffset(uint32_t offset);
intptr_t GetDataSize() const;
intptr_t GetTextSize() const;
Snapshot::Kind kind() const { return kind_; }
intptr_t next_ref_index() const { return next_ref_index_; }
@ -390,6 +359,36 @@ class Serializer : public ThreadStackResource {
void DumpCombinedCodeStatistics();
private:
static const char* ReadOnlyObjectType(intptr_t cid);
intptr_t WriteRefId(RawObject* object) {
intptr_t id = 0;
if (!object->IsHeapObject()) {
RawSmi* smi = Smi::RawCast(object);
id = smi_ids_.Lookup(smi)->id_;
if (id == 0) {
FATAL("Missing ref");
}
} else {
// The object id weak table holds image offsets for Instructions instead
// of ref indices.
ASSERT(!object->IsInstructions());
id = heap_->GetObjectId(object);
if (id == 0) {
if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
return WriteRefId(Object::null());
}
#if !defined(DART_PRECOMPILED_RUNTIME)
if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
return WriteRefId(Object::null());
}
#endif // !DART_PRECOMPILED_RUNTIME
FATAL("Missing ref");
}
}
return id;
}
Heap* heap_;
Zone* zone_;
Snapshot::Kind kind_;

View file

@ -292,7 +292,7 @@ void Dwarf::WriteCompilationUnit() {
uint8_t* buffer = nullptr;
WriteStream stream(&buffer, ZoneReallocate, 64 * KB);
AssemblyCodeNamer namer(zone_);
SnapshotTextObjectNamer namer(zone_);
if (asm_stream_ != nullptr) {
#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
@ -358,7 +358,7 @@ void Dwarf::WriteCompilationUnit() {
intptr_t last_code_index = codes_.length() - 1;
const Code& last_code = *(codes_[last_code_index]);
PrintNamedAddressWithOffset(
namer.AssemblyNameFor(last_code_index, last_code), last_code.Size());
namer.SnapshotNameFor(last_code_index, last_code), last_code.Size());
}
if (elf_ != nullptr) {
addr(elf_->NextMemoryOffset());
@ -421,7 +421,7 @@ void Dwarf::WriteAbstractFunctions() {
void Dwarf::WriteConcreteFunctions() {
Function& function = Function::Handle(zone_);
Script& script = Script::Handle(zone_);
AssemblyCodeNamer namer(zone_);
SnapshotTextObjectNamer namer(zone_);
for (intptr_t i = 0; i < codes_.length(); i++) {
const Code& code = *(codes_[i]);
RELEASE_ASSERT(!code.IsNull());
@ -456,7 +456,7 @@ void Dwarf::WriteConcreteFunctions() {
// DW_AT_low_pc
if (asm_stream_ != nullptr) {
const char* asm_name = namer.AssemblyNameFor(i, code);
const char* asm_name = namer.SnapshotNameFor(i, code);
// DW_AT_low_pc
PrintNamedAddress(asm_name);
// DW_AT_high_pc
@ -564,7 +564,7 @@ void Dwarf::WriteInliningNode(InliningNode* node,
intptr_t root_code_index,
intptr_t root_code_address,
const Script& parent_script,
AssemblyCodeNamer* namer) {
SnapshotTextObjectNamer* namer) {
RELEASE_ASSERT(elf_ == nullptr || root_code_address >= 0);
intptr_t file = LookupScript(parent_script);
intptr_t line = node->call_pos.value();
@ -587,7 +587,7 @@ void Dwarf::WriteInliningNode(InliningNode* node,
if (asm_stream_ != nullptr) {
const char* asm_name =
namer->AssemblyNameFor(root_code_index, *codes_[root_code_index]);
namer->SnapshotNameFor(root_code_index, *codes_[root_code_index]);
// DW_AT_low_pc
PrintNamedAddressWithOffset(asm_name, node->start_pc_offset);
// DW_AT_high_pc
@ -722,14 +722,14 @@ void Dwarf::WriteLines() {
Array& functions = Array::Handle(zone_);
GrowableArray<const Function*> function_stack(zone_, 8);
GrowableArray<TokenPosition> token_positions(zone_, 8);
AssemblyCodeNamer namer(zone_);
SnapshotTextObjectNamer namer(zone_);
for (intptr_t i = 0; i < codes_.length(); i++) {
const Code& code = *(codes_[i]);
const char* asm_name = nullptr;
if (asm_stream_ != nullptr) {
asm_name = namer.AssemblyNameFor(i, code);
asm_name = namer.SnapshotNameFor(i, code);
}
intptr_t current_code_address = -1;
@ -808,7 +808,7 @@ void Dwarf::WriteLines() {
} else {
u1(DW_LNS_advance_pc);
if (asm_stream_ != nullptr) {
const char* previous_asm_name = namer.AssemblyNameFor(
const char* previous_asm_name = namer.SnapshotNameFor(
previous_code_index, *codes_[previous_code_index]);
Print(".uleb128 %s - %s + %" Pd "\n", asm_name, previous_asm_name,
current_pc_offset - previous_pc_offset);
@ -859,9 +859,9 @@ void Dwarf::WriteLines() {
u1(DW_LNS_advance_pc);
if (asm_stream_ != nullptr) {
const char* last_asm_name =
namer.AssemblyNameFor(last_code_index, last_code);
namer.SnapshotNameFor(last_code_index, last_code);
ASSERT(previous_code_index >= 0);
const char* previous_asm_name = namer.AssemblyNameFor(
const char* previous_asm_name = namer.SnapshotNameFor(
previous_code_index, *codes_[previous_code_index]);
Print(".uleb128 %s - %s + %" Pd "\n", last_asm_name, previous_asm_name,
last_code.Size() - previous_pc_offset);

View file

@ -16,7 +16,7 @@ namespace dart {
class Elf;
class InliningNode;
class AssemblyCodeNamer;
class SnapshotTextObjectNamer;
struct ScriptIndexPair {
// Typedefs needed for the DirectChainedHashMap template.
@ -393,7 +393,7 @@ class Dwarf : public ZoneAllocated {
intptr_t root_code_index,
intptr_t root_code_offset,
const Script& parent_script,
AssemblyCodeNamer* namer);
SnapshotTextObjectNamer* namer);
void WriteLines();
const char* Deobfuscate(const char* cstr);

View file

@ -78,15 +78,21 @@ bool ObjectOffsetTrait::IsKeyEqual(Pair pair, Key key) {
}
#if !defined(DART_PRECOMPILED_RUNTIME)
ImageWriter::ImageWriter(Heap* heap)
: heap_(heap),
ImageWriter::ImageWriter(Thread* t)
: heap_(t->heap()),
next_data_offset_(0),
next_text_offset_(0),
objects_(),
instructions_() {
instructions_(),
instructions_section_type_(
TagObjectTypeAsReadOnly(t->zone(), "InstructionsSection")),
instructions_type_(TagObjectTypeAsReadOnly(t->zone(), "Instructions")),
trampoline_type_(TagObjectTypeAsReadOnly(t->zone(), "Trampoline")) {
ResetOffsets();
}
ImageWriter::~ImageWriter() {}
void ImageWriter::PrepareForSerialization(
GrowableArray<ImageWriterCommand>* commands) {
if (commands != nullptr) {
@ -243,6 +249,42 @@ uint32_t ImageWriter::GetDataOffsetFor(RawObject* raw_object) {
return offset;
}
intptr_t ImageWriter::GetTextObjectCount() const {
return instructions_.length();
}
void ImageWriter::GetTrampolineInfo(intptr_t* count, intptr_t* size) const {
ASSERT(count != nullptr && size != nullptr);
*count = 0;
*size = 0;
for (auto const data : instructions_) {
if (data.trampoline_length != 0) {
*count += 1;
*size += data.trampoline_length;
}
}
}
// Returns nullptr if there is no profile writer.
const char* ImageWriter::ObjectTypeForProfile(const Object& object) const {
if (profile_writer_ == nullptr) return nullptr;
ASSERT(IsROSpace());
Thread* thread = Thread::Current();
REUSABLE_CLASS_HANDLESCOPE(thread);
REUSABLE_STRING_HANDLESCOPE(thread);
Class& klass = thread->ClassHandle();
String& name = thread->StringHandle();
klass = object.clazz();
name = klass.UserVisibleName();
auto const name_str = name.ToCString();
return TagObjectTypeAsReadOnly(thread->zone(), name_str);
}
const char* ImageWriter::TagObjectTypeAsReadOnly(Zone* zone, const char* type) {
ASSERT(zone != nullptr && type != nullptr);
return OS::SCreate(zone, "(RO) %s", type);
}
#if defined(DART_PRECOMPILER)
void ImageWriter::DumpInstructionStats() {
std::unique_ptr<CombinedCodeStatistics> instruction_stats(
@ -461,7 +503,7 @@ AssemblyImageWriter::AssemblyImageWriter(Thread* thread,
void* callback_data,
bool strip,
Elf* debug_elf)
: ImageWriter(thread->heap()),
: ImageWriter(thread),
assembly_stream_(512 * KB, callback, callback_data),
assembly_dwarf_(nullptr),
debug_dwarf_(nullptr) {
@ -537,37 +579,47 @@ static const char* NameOfStubIsolateSpecificStub(ObjectStore* object_store,
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
const char* AssemblyCodeNamer::AssemblyNameFor(intptr_t code_index,
const Code& code) {
const char* SnapshotTextObjectNamer::SnapshotNameFor(intptr_t code_index,
const Code& code) {
ASSERT(!code.IsNull());
const char* prefix = FLAG_precompiled_mode ? "Precompiled_" : "";
owner_ = code.owner();
if (owner_.IsNull()) {
insns_ = code.instructions();
const char* name = StubCode::NameOfStub(insns_.EntryPoint());
if (name != nullptr) {
return OS::SCreate(zone_, "Precompiled_Stub_%s", name);
return OS::SCreate(zone_, "%sStub_%s", prefix, name);
}
name = NameOfStubIsolateSpecificStub(store_, code);
ASSERT(name != nullptr);
return OS::SCreate(zone_, "Precompiled__%s", name);
return OS::SCreate(zone_, "%s_%s", prefix, name);
} else if (owner_.IsClass()) {
string_ = Class::Cast(owner_).Name();
const char* name = string_.ToCString();
EnsureAssemblerIdentifier(const_cast<char*>(name));
return OS::SCreate(zone_, "Precompiled_AllocationStub_%s_%" Pd, name,
return OS::SCreate(zone_, "%sAllocationStub_%s_%" Pd, prefix, name,
code_index);
} else if (owner_.IsAbstractType()) {
const char* name = namer_.StubNameForType(AbstractType::Cast(owner_));
return OS::SCreate(zone_, "Precompiled_%s", name);
return OS::SCreate(zone_, "%s%s", prefix, name);
} else if (owner_.IsFunction()) {
const char* name = Function::Cast(owner_).ToQualifiedCString();
EnsureAssemblerIdentifier(const_cast<char*>(name));
return OS::SCreate(zone_, "Precompiled_%s_%" Pd, name, code_index);
return OS::SCreate(zone_, "%s%s_%" Pd, prefix, name, code_index);
} else {
UNREACHABLE();
}
}
const char* SnapshotTextObjectNamer::SnapshotNameFor(
intptr_t index,
const ImageWriter::InstructionsData& data) {
if (data.trampoline_bytes != nullptr) {
return OS::SCreate(zone_, "Trampoline_%" Pd "", index);
}
return SnapshotNameFor(index, *data.code_);
}
void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
@ -614,6 +666,10 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
WriteWordLiteralText(0);
}
// Only valid if bare_instruction_payloads is true.
const V8SnapshotProfileWriter::ObjectId instructions_section_id(
offset_space_, bare_instruction_payloads ? Image::kHeaderSize : -1);
if (bare_instruction_payloads) {
const intptr_t section_size = image_size - Image::kHeaderSize;
// Add the RawInstructionsSection header.
@ -633,15 +689,14 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
WriteWordLiteralText(instructions_length);
if (profile_writer_ != nullptr) {
const intptr_t offset = Image::kHeaderSize;
const intptr_t non_instruction_bytes =
compiler::target::InstructionsSection::HeaderSize();
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
"InstructionsSection",
/*name=*/nullptr);
profile_writer_->AttributeBytesTo({offset_space_, offset},
profile_writer_->SetObjectTypeAndName(instructions_section_id,
instructions_section_type_,
instructions_symbol);
profile_writer_->AttributeBytesTo(instructions_section_id,
non_instruction_bytes);
profile_writer_->AddRoot({offset_space_, offset});
profile_writer_->AddRoot(instructions_section_id);
}
}
@ -654,7 +709,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
FrameUnwindPrologue();
PcDescriptors& descriptors = PcDescriptors::Handle(zone);
AssemblyCodeNamer namer(zone);
SnapshotTextObjectNamer namer(zone);
intptr_t text_offset = 0;
ASSERT(offset_space_ != V8SnapshotProfileWriter::kSnapshot);
@ -663,28 +718,37 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const bool is_trampoline = data.trampoline_bytes != nullptr;
ASSERT((data.text_offset_ - instructions_[0].text_offset_) == text_offset);
if (bare_instruction_payloads && profile_writer_ != nullptr) {
const intptr_t instructions_sections_offset = Image::kHeaderSize;
const intptr_t offset = section_headers_size + text_offset;
profile_writer_->AttributeReferenceTo(
{offset_space_, instructions_sections_offset},
{{offset_space_, offset},
V8SnapshotProfileWriter::Reference::kElement,
text_offset});
intptr_t dwarf_index = i;
#if defined(DART_PRECOMPILER)
if (!is_trampoline && assembly_dwarf_ != nullptr) {
dwarf_index = assembly_dwarf_->AddCode(*data.code_);
}
#endif
const auto object_name = namer.SnapshotNameFor(dwarf_index, data);
if (profile_writer_ != nullptr) {
const auto object_offset = section_headers_size + text_offset;
const V8SnapshotProfileWriter::ObjectId object_id(offset_space_,
object_offset);
auto const type = is_trampoline ? trampoline_type_ : instructions_type_;
const intptr_t size = is_trampoline ? data.trampoline_length
: SizeInSnapshot(data.insns_->raw());
profile_writer_->SetObjectTypeAndName(object_id, type, object_name);
profile_writer_->AttributeBytesTo(object_id, size);
// If the object is wrapped in an InstructionSection, then add an
// element reference.
if (bare_instruction_payloads) {
profile_writer_->AttributeReferenceTo(
instructions_section_id,
{object_id, V8SnapshotProfileWriter::Reference::kElement,
text_offset});
}
}
if (is_trampoline) {
if (profile_writer_ != nullptr) {
const intptr_t offset = section_headers_size + text_offset;
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
"Trampolines",
/*name=*/nullptr);
profile_writer_->AttributeBytesTo({offset_space_, offset},
data.trampline_length);
}
const auto start = reinterpret_cast<uword>(data.trampoline_bytes);
const auto end = start + data.trampline_length;
const auto end = start + data.trampoline_length;
text_offset += WriteByteSequence(start, end);
delete[] data.trampoline_bytes;
data.trampoline_bytes = nullptr;
@ -694,18 +758,8 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const intptr_t instr_start = text_offset;
const Instructions& insns = *data.insns_;
const Code& code = *data.code_;
descriptors = data.code_->pc_descriptors();
if (profile_writer_ != nullptr) {
const intptr_t offset = section_headers_size + text_offset;
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
"Instructions",
/*name=*/nullptr);
profile_writer_->AttributeBytesTo({offset_space_, offset},
SizeInSnapshot(insns.raw()));
}
const uword payload_start = insns.PayloadStart();
// 1. Write from the object start to the payload start. This includes the
@ -746,21 +800,16 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
compiler::target::Instructions::HeaderSize());
}
intptr_t dwarf_index = i;
#ifdef DART_PRECOMPILER
// Create a label for use by DWARF.
if (assembly_dwarf_ != nullptr) {
dwarf_index = assembly_dwarf_->AddCode(code);
}
#if defined(DART_PRECOMPILER)
if (debug_dwarf_ != nullptr) {
auto const virtual_address =
debug_segment_base + section_headers_size + text_offset;
debug_dwarf_->AddCode(code, virtual_address);
debug_dwarf_->AddCode(*data.code_, virtual_address);
}
#endif
// 2. Write a label at the entry point.
// Linux's perf uses these labels.
assembly_stream_.Print("%s:\n", namer.AssemblyNameFor(dwarf_index, code));
assembly_stream_.Print("%s:\n", object_name);
{
// 3. Write from the payload start to payload end. For AOT snapshots
@ -1005,7 +1054,7 @@ BlobImageWriter::BlobImageWriter(Thread* thread,
intptr_t bss_base,
Elf* elf,
Dwarf* elf_dwarf)
: ImageWriter(thread->heap()),
: ImageWriter(thread),
instructions_blob_stream_(instructions_blob_buffer, alloc, initial_size),
elf_(elf),
elf_dwarf_(elf_dwarf),
@ -1030,8 +1079,11 @@ intptr_t BlobImageWriter::WriteByteSequence(uword start, uword end) {
void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const bool bare_instruction_payloads =
FLAG_precompiled_mode && FLAG_use_bare_instructions;
const char* instructions_symbol =
vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions";
auto const zone = Thread::Current()->zone();
#ifdef DART_PRECOMPILER
#if defined(DART_PRECOMPILER)
intptr_t segment_base = 0;
if (elf_ != nullptr) {
segment_base = elf_->NextMemoryOffset();
@ -1059,6 +1111,10 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
instructions_blob_stream_.WriteTargetWord(0);
}
// Only valid when bare_instructions_payloads is true.
const V8SnapshotProfileWriter::ObjectId instructions_section_id(
offset_space_, bare_instruction_payloads ? Image::kHeaderSize : -1);
if (bare_instruction_payloads) {
const intptr_t section_size = image_size - Image::kHeaderSize;
// Add the RawInstructionsSection header.
@ -1077,24 +1133,23 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
instructions_blob_stream_.WriteTargetWord(instructions_length);
if (profile_writer_ != nullptr) {
const intptr_t offset = Image::kHeaderSize;
const intptr_t non_instruction_bytes =
compiler::target::InstructionsSection::HeaderSize();
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
"InstructionsSection",
/*name=*/nullptr);
profile_writer_->AttributeBytesTo({offset_space_, offset},
profile_writer_->SetObjectTypeAndName(instructions_section_id,
instructions_section_type_,
instructions_symbol);
profile_writer_->AttributeBytesTo(instructions_section_id,
non_instruction_bytes);
profile_writer_->AddRoot({offset_space_, offset});
profile_writer_->AddRoot(instructions_section_id);
}
}
intptr_t text_offset = 0;
#if defined(DART_PRECOMPILER)
PcDescriptors& descriptors = PcDescriptors::Handle();
AssemblyCodeNamer namer(Thread::Current()->zone());
auto& descriptors = PcDescriptors::Handle(zone);
#endif
SnapshotTextObjectNamer namer(zone);
NoSafepointScope no_safepoint;
for (intptr_t i = 0; i < instructions_.length(); i++) {
@ -1102,18 +1157,29 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const bool is_trampoline = data.trampoline_bytes != nullptr;
ASSERT((data.text_offset_ - instructions_[0].text_offset_) == text_offset);
if (bare_instruction_payloads && profile_writer_ != nullptr) {
const intptr_t instructions_sections_offset = Image::kHeaderSize;
profile_writer_->AttributeReferenceTo(
{offset_space_, instructions_sections_offset},
{{offset_space_, instructions_blob_stream_.Position()},
V8SnapshotProfileWriter::Reference::kElement,
text_offset});
const auto object_name = namer.SnapshotNameFor(i, data);
if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId object_id(
offset_space_, instructions_blob_stream_.Position());
auto const type = is_trampoline ? trampoline_type_ : instructions_type_;
const intptr_t size = is_trampoline ? data.trampoline_length
: SizeInSnapshot(data.insns_->raw());
profile_writer_->SetObjectTypeAndName(object_id, type, object_name);
profile_writer_->AttributeBytesTo(object_id, size);
// If the object is wrapped in an InstructionSection, then add an
// element reference.
if (bare_instruction_payloads) {
profile_writer_->AttributeReferenceTo(
instructions_section_id,
{object_id, V8SnapshotProfileWriter::Reference::kElement,
text_offset});
}
}
if (is_trampoline) {
const auto start = reinterpret_cast<uword>(data.trampoline_bytes);
const auto end = start + data.trampline_length;
const auto end = start + data.trampoline_length;
text_offset += WriteByteSequence(start, end);
delete[] data.trampoline_bytes;
data.trampoline_bytes = nullptr;
@ -1123,7 +1189,6 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const intptr_t instr_start = text_offset;
const Instructions& insns = *instructions_[i].insns_;
AutoTraceImage(insns, 0, &this->instructions_blob_stream_);
const uword payload_start = insns.PayloadStart();
ASSERT(Utils::IsAligned(payload_start, sizeof(compiler::target::uword)));
@ -1190,13 +1255,16 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const auto& code = *instructions_[i].code_;
auto const virtual_address = segment_base + payload_stream_start;
elf_dwarf_->AddCode(code, virtual_address);
elf_->AddStaticSymbol(elf_->NextSectionIndex(),
namer.AssemblyNameFor(i, code), virtual_address);
elf_->AddStaticSymbol(elf_->NextSectionIndex(), object_name,
virtual_address);
}
if (debug_dwarf_ != nullptr) {
const auto& code = *instructions_[i].code_;
auto const virtual_address = debug_segment_base + payload_stream_start;
debug_dwarf_->AddCode(code, virtual_address);
auto const elf = debug_dwarf_->elf();
elf->AddStaticSymbol(elf->NextSectionIndex(), object_name,
virtual_address);
}
// Don't patch the relocation if we're not generating ELF. The regular blobs
@ -1253,8 +1321,6 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
ASSERT_EQUAL(instructions_blob_stream_.bytes_written(), image_size);
#ifdef DART_PRECOMPILER
const char* instructions_symbol =
vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions";
if (elf_ != nullptr) {
auto const segment_base2 =
elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),

View file

@ -149,8 +149,8 @@ struct ImageWriterCommand {
class ImageWriter : public ValueObject {
public:
explicit ImageWriter(Heap* heap);
virtual ~ImageWriter() {}
explicit ImageWriter(Thread* thread);
virtual ~ImageWriter();
void ResetOffsets() {
next_data_offset_ = Image::kHeaderSize;
@ -166,12 +166,20 @@ class ImageWriter : public ValueObject {
// [ImageWriterCommand]s.
void PrepareForSerialization(GrowableArray<ImageWriterCommand>* commands);
bool IsROSpace() const {
return offset_space_ == V8SnapshotProfileWriter::kVmData ||
offset_space_ == V8SnapshotProfileWriter::kVmText ||
offset_space_ == V8SnapshotProfileWriter::kIsolateData ||
offset_space_ == V8SnapshotProfileWriter::kIsolateText;
}
int32_t GetTextOffsetFor(RawInstructions* instructions, RawCode* code);
uint32_t GetDataOffsetFor(RawObject* raw_object);
void Write(WriteStream* clustered_stream, bool vm);
intptr_t data_size() const { return next_data_offset_; }
intptr_t text_size() const { return next_text_offset_; }
intptr_t GetTextObjectCount() const;
void GetTrampolineInfo(intptr_t* count, intptr_t* size) const;
void DumpStatistics();
@ -215,6 +223,10 @@ class ImageWriter : public ValueObject {
marked_tags);
}
// Returns nullptr if there is no profile writer.
const char* ObjectTypeForProfile(const Object& object) const;
static const char* TagObjectTypeAsReadOnly(Zone* zone, const char* type);
protected:
void WriteROData(WriteStream* stream);
virtual void WriteText(WriteStream* clustered_stream, bool vm) = 0;
@ -230,16 +242,16 @@ class ImageWriter : public ValueObject {
raw_code_(code),
text_offset_(text_offset),
trampoline_bytes(nullptr),
trampline_length(0) {}
trampoline_length(0) {}
InstructionsData(uint8_t* trampoline_bytes,
intptr_t trampline_length,
intptr_t trampoline_length,
intptr_t text_offset)
: raw_insns_(nullptr),
raw_code_(nullptr),
text_offset_(text_offset),
trampoline_bytes(trampoline_bytes),
trampline_length(trampline_length) {}
trampoline_length(trampoline_length) {}
union {
RawInstructions* raw_insns_;
@ -252,7 +264,7 @@ class ImageWriter : public ValueObject {
intptr_t text_offset_;
uint8_t* trampoline_bytes;
intptr_t trampline_length;
intptr_t trampoline_length;
};
struct ObjectData {
@ -273,9 +285,13 @@ class ImageWriter : public ValueObject {
V8SnapshotProfileWriter::IdSpace offset_space_ =
V8SnapshotProfileWriter::kSnapshot;
V8SnapshotProfileWriter* profile_writer_ = nullptr;
const char* const instructions_section_type_;
const char* const instructions_type_;
const char* const trampoline_type_;
template <class T>
friend class TraceImageObjectScope;
friend class SnapshotTextObjectNamer; // For InstructionsData.
private:
DISALLOW_COPY_AND_ASSIGN(ImageWriter);
@ -293,43 +309,34 @@ class TraceImageObjectScope {
intptr_t section_offset,
const T* stream,
const Object& object)
: writer_(writer),
stream_(stream),
: writer_(ASSERT_NOTNULL(writer)),
stream_(ASSERT_NOTNULL(stream)),
section_offset_(section_offset),
start_offset_(stream_->Position() - section_offset) {
if (writer_->profile_writer_ != nullptr) {
Thread* thread = Thread::Current();
REUSABLE_CLASS_HANDLESCOPE(thread);
REUSABLE_STRING_HANDLESCOPE(thread);
Class& klass = thread->ClassHandle();
String& name = thread->StringHandle();
klass = object.clazz();
name = klass.UserVisibleName();
ASSERT(writer_->offset_space_ != V8SnapshotProfileWriter::kSnapshot);
writer_->profile_writer_->SetObjectTypeAndName(
{writer_->offset_space_, start_offset_}, name.ToCString(), nullptr);
}
}
start_offset_(stream_->Position() - section_offset),
object_(object) {}
~TraceImageObjectScope() {
if (writer_->profile_writer_ != nullptr) {
ASSERT(writer_->offset_space_ != V8SnapshotProfileWriter::kSnapshot);
writer_->profile_writer_->AttributeBytesTo(
{writer_->offset_space_, start_offset_},
stream_->Position() - section_offset_ - start_offset_);
}
if (writer_->profile_writer_ == nullptr) return;
ASSERT(writer_->IsROSpace());
writer_->profile_writer_->SetObjectTypeAndName(
{writer_->offset_space_, start_offset_},
writer_->ObjectTypeForProfile(object_), nullptr);
writer_->profile_writer_->AttributeBytesTo(
{writer_->offset_space_, start_offset_},
stream_->Position() - section_offset_ - start_offset_);
}
private:
ImageWriter* writer_;
const T* stream_;
intptr_t section_offset_;
intptr_t start_offset_;
ImageWriter* const writer_;
const T* const stream_;
const intptr_t section_offset_;
const intptr_t start_offset_;
const Object& object_;
};
class AssemblyCodeNamer {
class SnapshotTextObjectNamer {
public:
explicit AssemblyCodeNamer(Zone* zone)
explicit SnapshotTextObjectNamer(Zone* zone)
: zone_(zone),
owner_(Object::Handle(zone)),
string_(String::Handle(zone)),
@ -338,7 +345,9 @@ class AssemblyCodeNamer {
const char* StubNameForType(const AbstractType& type) const;
const char* AssemblyNameFor(intptr_t code_index, const Code& code);
const char* SnapshotNameFor(intptr_t code_index, const Code& code);
const char* SnapshotNameFor(intptr_t index,
const ImageWriter::InstructionsData& data);
private:
Zone* const zone_;